@openrewrite/rewrite 8.72.2 → 8.72.4

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 (197) hide show
  1. package/dist/execution.js +3 -16
  2. package/dist/execution.js.map +1 -1
  3. package/dist/index.js +34 -49
  4. package/dist/index.js.map +1 -1
  5. package/dist/java/markers.js +12 -29
  6. package/dist/java/markers.js.map +1 -1
  7. package/dist/java/print.js +2 -13
  8. package/dist/java/print.js.map +1 -1
  9. package/dist/java/rpc.js +1344 -1725
  10. package/dist/java/rpc.js.map +1 -1
  11. package/dist/java/type-visitor.js +143 -184
  12. package/dist/java/type-visitor.js.map +1 -1
  13. package/dist/java/visitor.js +1072 -1249
  14. package/dist/java/visitor.js.map +1 -1
  15. package/dist/javascript/add-import.js +495 -534
  16. package/dist/javascript/add-import.js.map +1 -1
  17. package/dist/javascript/autodetect.js +116 -159
  18. package/dist/javascript/autodetect.js.map +1 -1
  19. package/dist/javascript/cleanup/add-parse-int-radix.js +41 -57
  20. package/dist/javascript/cleanup/add-parse-int-radix.js.map +1 -1
  21. package/dist/javascript/cleanup/prefer-optional-chain.js +89 -105
  22. package/dist/javascript/cleanup/prefer-optional-chain.js.map +1 -1
  23. package/dist/javascript/cleanup/use-object-property-shorthand.js +74 -95
  24. package/dist/javascript/cleanup/use-object-property-shorthand.js.map +1 -1
  25. package/dist/javascript/comparator.js +815 -1167
  26. package/dist/javascript/comparator.js.map +1 -1
  27. package/dist/javascript/dependency-workspace.js +206 -219
  28. package/dist/javascript/dependency-workspace.js.map +1 -1
  29. package/dist/javascript/format/format.js +682 -908
  30. package/dist/javascript/format/format.js.map +1 -1
  31. package/dist/javascript/format/minimum-viable-spacing-visitor.js +152 -231
  32. package/dist/javascript/format/minimum-viable-spacing-visitor.js.map +1 -1
  33. package/dist/javascript/format/normalize-whitespace-visitor.js +12 -31
  34. package/dist/javascript/format/normalize-whitespace-visitor.js.map +1 -1
  35. package/dist/javascript/format/prettier-config-loader.js +134 -153
  36. package/dist/javascript/format/prettier-config-loader.js.map +1 -1
  37. package/dist/javascript/format/prettier-format.js +112 -129
  38. package/dist/javascript/format/prettier-format.js.map +1 -1
  39. package/dist/javascript/format/tabs-and-indents-visitor.js +112 -136
  40. package/dist/javascript/format/tabs-and-indents-visitor.js.map +1 -1
  41. package/dist/javascript/markers.js +59 -92
  42. package/dist/javascript/markers.js.map +1 -1
  43. package/dist/javascript/migrate/es6/modernize-octal-escape-sequences.js +39 -52
  44. package/dist/javascript/migrate/es6/modernize-octal-escape-sequences.js.map +1 -1
  45. package/dist/javascript/migrate/es6/modernize-octal-literals.js +25 -38
  46. package/dist/javascript/migrate/es6/modernize-octal-literals.js.map +1 -1
  47. package/dist/javascript/migrate/es6/remove-duplicate-object-keys.js +66 -82
  48. package/dist/javascript/migrate/es6/remove-duplicate-object-keys.js.map +1 -1
  49. package/dist/javascript/migrate/typescript/export-assignment-to-export-default.js +10 -23
  50. package/dist/javascript/migrate/typescript/export-assignment-to-export-default.js.map +1 -1
  51. package/dist/javascript/node-resolution-result.js +137 -166
  52. package/dist/javascript/node-resolution-result.js.map +1 -1
  53. package/dist/javascript/package-json-parser.js +312 -343
  54. package/dist/javascript/package-json-parser.js.map +1 -1
  55. package/dist/javascript/package-manager.js +145 -170
  56. package/dist/javascript/package-manager.js.map +1 -1
  57. package/dist/javascript/parser.d.ts.map +1 -1
  58. package/dist/javascript/parser.js +94 -68
  59. package/dist/javascript/parser.js.map +1 -1
  60. package/dist/javascript/print.js +1572 -1835
  61. package/dist/javascript/print.js.map +1 -1
  62. package/dist/javascript/project-parser.js +151 -172
  63. package/dist/javascript/project-parser.js.map +1 -1
  64. package/dist/javascript/recipes/add-dependency.js +140 -175
  65. package/dist/javascript/recipes/add-dependency.js.map +1 -1
  66. package/dist/javascript/recipes/async-callback-in-sync-array-method.js +20 -36
  67. package/dist/javascript/recipes/async-callback-in-sync-array-method.js.map +1 -1
  68. package/dist/javascript/recipes/auto-format.js +3 -14
  69. package/dist/javascript/recipes/auto-format.js.map +1 -1
  70. package/dist/javascript/recipes/change-import.js +447 -495
  71. package/dist/javascript/recipes/change-import.js.map +1 -1
  72. package/dist/javascript/recipes/order-imports.js +162 -175
  73. package/dist/javascript/recipes/order-imports.js.map +1 -1
  74. package/dist/javascript/recipes/upgrade-dependency-version.js +167 -197
  75. package/dist/javascript/recipes/upgrade-dependency-version.js.map +1 -1
  76. package/dist/javascript/recipes/upgrade-transitive-dependency-version.js +166 -193
  77. package/dist/javascript/recipes/upgrade-transitive-dependency-version.js.map +1 -1
  78. package/dist/javascript/remove-import.js +689 -724
  79. package/dist/javascript/remove-import.js.map +1 -1
  80. package/dist/javascript/rpc.js +1007 -1332
  81. package/dist/javascript/rpc.js.map +1 -1
  82. package/dist/javascript/search/find-dependency.js +84 -110
  83. package/dist/javascript/search/find-dependency.js.map +1 -1
  84. package/dist/javascript/search/uses-method.js +5 -19
  85. package/dist/javascript/search/uses-method.js.map +1 -1
  86. package/dist/javascript/search/uses-type.js +9 -20
  87. package/dist/javascript/search/uses-type.js.map +1 -1
  88. package/dist/javascript/templating/comparator.js +737 -822
  89. package/dist/javascript/templating/comparator.js.map +1 -1
  90. package/dist/javascript/templating/engine.js +211 -245
  91. package/dist/javascript/templating/engine.js.map +1 -1
  92. package/dist/javascript/templating/pattern.js +169 -190
  93. package/dist/javascript/templating/pattern.js.map +1 -1
  94. package/dist/javascript/templating/placeholder-replacement.js +172 -210
  95. package/dist/javascript/templating/placeholder-replacement.js.map +1 -1
  96. package/dist/javascript/templating/rewrite.js +75 -97
  97. package/dist/javascript/templating/rewrite.js.map +1 -1
  98. package/dist/javascript/templating/template.js +69 -82
  99. package/dist/javascript/templating/template.js.map +1 -1
  100. package/dist/javascript/tree-debug.js +109 -137
  101. package/dist/javascript/tree-debug.js.map +1 -1
  102. package/dist/javascript/visitor.js +1090 -1254
  103. package/dist/javascript/visitor.js.map +1 -1
  104. package/dist/json/print.js +72 -103
  105. package/dist/json/print.js.map +1 -1
  106. package/dist/json/rpc.js +120 -181
  107. package/dist/json/rpc.js.map +1 -1
  108. package/dist/json/visitor.js +69 -100
  109. package/dist/json/visitor.js.map +1 -1
  110. package/dist/marketplace.js +20 -33
  111. package/dist/marketplace.js.map +1 -1
  112. package/dist/parse-error.js +41 -62
  113. package/dist/parse-error.js.map +1 -1
  114. package/dist/parser.js +7 -18
  115. package/dist/parser.js.map +1 -1
  116. package/dist/path-utils.js +46 -59
  117. package/dist/path-utils.js.map +1 -1
  118. package/dist/preconditions.js +30 -47
  119. package/dist/preconditions.js.map +1 -1
  120. package/dist/print.js +6 -19
  121. package/dist/print.js.map +1 -1
  122. package/dist/recipe.js +42 -73
  123. package/dist/recipe.js.map +1 -1
  124. package/dist/rpc/index.js +74 -115
  125. package/dist/rpc/index.js.map +1 -1
  126. package/dist/rpc/queue.js +71 -90
  127. package/dist/rpc/queue.js.map +1 -1
  128. package/dist/rpc/recipe.js +32 -57
  129. package/dist/rpc/recipe.js.map +1 -1
  130. package/dist/rpc/request/generate.js +4 -13
  131. package/dist/rpc/request/generate.js.map +1 -1
  132. package/dist/rpc/request/get-languages.js +2 -11
  133. package/dist/rpc/request/get-languages.js.map +1 -1
  134. package/dist/rpc/request/get-marketplace.js +9 -20
  135. package/dist/rpc/request/get-marketplace.js.map +1 -1
  136. package/dist/rpc/request/get-object.js +4 -13
  137. package/dist/rpc/request/get-object.js.map +1 -1
  138. package/dist/rpc/request/install-recipes.js +25 -36
  139. package/dist/rpc/request/install-recipes.js.map +1 -1
  140. package/dist/rpc/request/metrics.js +8 -17
  141. package/dist/rpc/request/metrics.js.map +1 -1
  142. package/dist/rpc/request/parse-project.js +36 -45
  143. package/dist/rpc/request/parse-project.js.map +1 -1
  144. package/dist/rpc/request/parse.js +5 -14
  145. package/dist/rpc/request/parse.js.map +1 -1
  146. package/dist/rpc/request/prepare-recipe.js +37 -52
  147. package/dist/rpc/request/prepare-recipe.js.map +1 -1
  148. package/dist/rpc/request/print.js +5 -14
  149. package/dist/rpc/request/print.js.map +1 -1
  150. package/dist/rpc/request/visit.js +56 -71
  151. package/dist/rpc/request/visit.js.map +1 -1
  152. package/dist/rpc/rewrite-rpc.js +70 -97
  153. package/dist/rpc/rewrite-rpc.js.map +1 -1
  154. package/dist/rpc/server.js +76 -89
  155. package/dist/rpc/server.js.map +1 -1
  156. package/dist/run.js +47 -66
  157. package/dist/run.js.map +1 -1
  158. package/dist/search/is-source-file.js +8 -19
  159. package/dist/search/is-source-file.js.map +1 -1
  160. package/dist/test/rewrite-test.js +154 -188
  161. package/dist/test/rewrite-test.js.map +1 -1
  162. package/dist/text/print.js +23 -38
  163. package/dist/text/print.js.map +1 -1
  164. package/dist/text/rpc.js +29 -44
  165. package/dist/text/rpc.js.map +1 -1
  166. package/dist/text/visitor.js +16 -33
  167. package/dist/text/visitor.js.map +1 -1
  168. package/dist/util.js +13 -24
  169. package/dist/util.js.map +1 -1
  170. package/dist/version.txt +1 -1
  171. package/dist/visitor.js +84 -115
  172. package/dist/visitor.js.map +1 -1
  173. package/dist/yaml/index.d.ts +2 -0
  174. package/dist/yaml/index.d.ts.map +1 -1
  175. package/dist/yaml/index.js +2 -0
  176. package/dist/yaml/index.js.map +1 -1
  177. package/dist/yaml/markers.d.ts +21 -0
  178. package/dist/yaml/markers.d.ts.map +1 -0
  179. package/dist/yaml/markers.js +37 -0
  180. package/dist/yaml/markers.js.map +1 -0
  181. package/dist/yaml/parser.d.ts.map +1 -1
  182. package/dist/yaml/parser.js +4 -1
  183. package/dist/yaml/parser.js.map +1 -1
  184. package/dist/yaml/print.d.ts +1 -1
  185. package/dist/yaml/print.d.ts.map +1 -1
  186. package/dist/yaml/print.js +175 -208
  187. package/dist/yaml/print.js.map +1 -1
  188. package/dist/yaml/rpc.js +154 -219
  189. package/dist/yaml/rpc.js.map +1 -1
  190. package/dist/yaml/visitor.js +78 -113
  191. package/dist/yaml/visitor.js.map +1 -1
  192. package/package.json +1 -1
  193. package/src/javascript/parser.ts +56 -14
  194. package/src/yaml/index.ts +2 -0
  195. package/src/yaml/markers.ts +70 -0
  196. package/src/yaml/parser.ts +5 -1
  197. package/src/yaml/print.ts +5 -2
@@ -1,13 +1,4 @@
1
1
  "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
2
  Object.defineProperty(exports, "__esModule", { value: true });
12
3
  exports.DebugPatternMatchingComparator = exports.PatternMatchingComparator = void 0;
13
4
  /*
@@ -73,51 +64,46 @@ class PatternMatchingComparator extends comparator_1.JavaScriptSemanticComparato
73
64
  captures: new CaptureMapImpl(state.storage)
74
65
  };
75
66
  }
76
- visit(j, p, parent) {
77
- const _super = Object.create(null, {
78
- visit: { get: () => super.visit }
79
- });
80
- return __awaiter(this, void 0, void 0, function* () {
81
- // Check if the pattern node is a capture - this handles unwrapped captures
82
- // (Wrapped captures in J.RightPadded are handled by visitRightPadded override)
83
- // Note: targetCursor will be pushed by parent's visit() method after this check
84
- const captureMarker = utils_1.PlaceholderUtils.getCaptureMarker(j);
85
- if (captureMarker) {
86
- // Push targetCursor to position it at the captured node for constraint evaluation
87
- // Only create cursor if targetCursor was initialized (meaning user provided one)
88
- const savedTargetCursor = this.targetCursor;
89
- const cursorAtCapturedNode = this.targetCursor !== undefined
90
- ? new __1.Cursor(p, this.targetCursor)
91
- : new __1.Cursor(p);
92
- this.targetCursor = cursorAtCapturedNode;
93
- try {
94
- // Evaluate constraint with context (cursor + previous captures)
95
- // Skip constraint for variadic captures - they're evaluated in matchSequence with the full array
96
- if (captureMarker.constraint && !captureMarker.variadicOptions) {
97
- const context = this.buildConstraintContext(cursorAtCapturedNode);
98
- if (!captureMarker.constraint(p, context)) {
99
- const captureName = captureMarker.captureName || 'unnamed';
100
- const targetKind = p.kind || 'unknown';
101
- return this.constraintFailed(captureName, targetKind);
102
- }
103
- }
104
- const success = this.matcher.handleCapture(captureMarker, p, undefined);
105
- if (!success) {
67
+ async visit(j, p, parent) {
68
+ // Check if the pattern node is a capture - this handles unwrapped captures
69
+ // (Wrapped captures in J.RightPadded are handled by visitRightPadded override)
70
+ // Note: targetCursor will be pushed by parent's visit() method after this check
71
+ const captureMarker = utils_1.PlaceholderUtils.getCaptureMarker(j);
72
+ if (captureMarker) {
73
+ // Push targetCursor to position it at the captured node for constraint evaluation
74
+ // Only create cursor if targetCursor was initialized (meaning user provided one)
75
+ const savedTargetCursor = this.targetCursor;
76
+ const cursorAtCapturedNode = this.targetCursor !== undefined
77
+ ? new __1.Cursor(p, this.targetCursor)
78
+ : new __1.Cursor(p);
79
+ this.targetCursor = cursorAtCapturedNode;
80
+ try {
81
+ // Evaluate constraint with context (cursor + previous captures)
82
+ // Skip constraint for variadic captures - they're evaluated in matchSequence with the full array
83
+ if (captureMarker.constraint && !captureMarker.variadicOptions) {
84
+ const context = this.buildConstraintContext(cursorAtCapturedNode);
85
+ if (!captureMarker.constraint(p, context)) {
106
86
  const captureName = captureMarker.captureName || 'unnamed';
107
- return this.captureConflict(captureName);
87
+ const targetKind = p.kind || 'unknown';
88
+ return this.constraintFailed(captureName, targetKind);
108
89
  }
109
- return j;
110
90
  }
111
- finally {
112
- this.targetCursor = savedTargetCursor;
91
+ const success = this.matcher.handleCapture(captureMarker, p, undefined);
92
+ if (!success) {
93
+ const captureName = captureMarker.captureName || 'unnamed';
94
+ return this.captureConflict(captureName);
113
95
  }
114
- }
115
- if (!this.match) {
116
96
  return j;
117
97
  }
118
- // Continue with parent's visit which will push targetCursor and traverse
119
- return yield _super.visit.call(this, j, p, parent);
120
- });
98
+ finally {
99
+ this.targetCursor = savedTargetCursor;
100
+ }
101
+ }
102
+ if (!this.match) {
103
+ return j;
104
+ }
105
+ // Continue with parent's visit which will push targetCursor and traverse
106
+ return await super.visit(j, p, parent);
121
107
  }
122
108
  hasSameKind(j, other) {
123
109
  return super.hasSameKind(j, other) ||
@@ -140,102 +126,92 @@ class PatternMatchingComparator extends comparator_1.JavaScriptSemanticComparato
140
126
  * Override visitRightPadded to check if this wrapper has a CaptureMarker.
141
127
  * If so, capture the entire wrapper (to preserve markers like semicolons).
142
128
  */
143
- visitRightPadded(right, p) {
144
- const _super = Object.create(null, {
145
- visitRightPadded: { get: () => super.visitRightPadded }
146
- });
147
- return __awaiter(this, void 0, void 0, function* () {
148
- if (!this.match) {
149
- return right;
150
- }
151
- // Check if this RightPadded has a CaptureMarker (attached during pattern construction)
152
- // Note: Markers are now only at the wrapper level, not at the element level
153
- const captureMarker = utils_1.PlaceholderUtils.getCaptureMarker(right);
154
- if (captureMarker) {
155
- // Extract the target wrapper if it's also a RightPadded
156
- const isRightPadded = p.kind === java_1.J.Kind.RightPadded;
157
- const targetWrapper = isRightPadded ? p : undefined;
158
- const targetElement = isRightPadded ? targetWrapper.element : p;
159
- // Push targetCursor to position it at the captured element for constraint evaluation
160
- const savedTargetCursor = this.targetCursor;
161
- const cursorAtCapturedNode = this.targetCursor !== undefined
162
- ? (targetWrapper ? new __1.Cursor(targetWrapper, this.targetCursor) : new __1.Cursor(targetElement, this.targetCursor))
163
- : (targetWrapper ? new __1.Cursor(targetWrapper) : new __1.Cursor(targetElement));
164
- this.targetCursor = cursorAtCapturedNode;
165
- try {
166
- // Evaluate constraint with cursor at the captured node (always defined)
167
- // Skip constraint for variadic captures - they're evaluated in matchSequence with the full array
168
- if (captureMarker.constraint && !captureMarker.variadicOptions && !captureMarker.constraint(targetElement, this.buildConstraintContext(cursorAtCapturedNode))) {
169
- const captureName = captureMarker.captureName || 'unnamed';
170
- const targetKind = targetElement.kind || 'unknown';
171
- return this.constraintFailed(captureName, targetKind);
172
- }
173
- // Handle the capture with the wrapper - use the element for pattern matching
174
- const success = this.matcher.handleCapture(captureMarker, targetElement, targetWrapper);
175
- if (!success) {
176
- const captureName = captureMarker.captureName || 'unnamed';
177
- return this.captureConflict(captureName);
178
- }
179
- return right;
129
+ async visitRightPadded(right, p) {
130
+ if (!this.match) {
131
+ return right;
132
+ }
133
+ // Check if this RightPadded has a CaptureMarker (attached during pattern construction)
134
+ // Note: Markers are now only at the wrapper level, not at the element level
135
+ const captureMarker = utils_1.PlaceholderUtils.getCaptureMarker(right);
136
+ if (captureMarker) {
137
+ // Extract the target wrapper if it's also a RightPadded
138
+ const isRightPadded = p.kind === java_1.J.Kind.RightPadded;
139
+ const targetWrapper = isRightPadded ? p : undefined;
140
+ const targetElement = isRightPadded ? targetWrapper.element : p;
141
+ // Push targetCursor to position it at the captured element for constraint evaluation
142
+ const savedTargetCursor = this.targetCursor;
143
+ const cursorAtCapturedNode = this.targetCursor !== undefined
144
+ ? (targetWrapper ? new __1.Cursor(targetWrapper, this.targetCursor) : new __1.Cursor(targetElement, this.targetCursor))
145
+ : (targetWrapper ? new __1.Cursor(targetWrapper) : new __1.Cursor(targetElement));
146
+ this.targetCursor = cursorAtCapturedNode;
147
+ try {
148
+ // Evaluate constraint with cursor at the captured node (always defined)
149
+ // Skip constraint for variadic captures - they're evaluated in matchSequence with the full array
150
+ if (captureMarker.constraint && !captureMarker.variadicOptions && !captureMarker.constraint(targetElement, this.buildConstraintContext(cursorAtCapturedNode))) {
151
+ const captureName = captureMarker.captureName || 'unnamed';
152
+ const targetKind = targetElement.kind || 'unknown';
153
+ return this.constraintFailed(captureName, targetKind);
180
154
  }
181
- finally {
182
- this.targetCursor = savedTargetCursor;
155
+ // Handle the capture with the wrapper - use the element for pattern matching
156
+ const success = this.matcher.handleCapture(captureMarker, targetElement, targetWrapper);
157
+ if (!success) {
158
+ const captureName = captureMarker.captureName || 'unnamed';
159
+ return this.captureConflict(captureName);
183
160
  }
161
+ return right;
184
162
  }
185
- // Not a capture wrapper - use parent implementation
186
- return _super.visitRightPadded.call(this, right, p);
187
- });
188
- }
189
- visitContainer(container, p) {
190
- const _super = Object.create(null, {
191
- visitContainer: { get: () => super.visitContainer }
192
- });
193
- return __awaiter(this, void 0, void 0, function* () {
194
- // Check if any elements are variadic captures
195
- const hasVariadicCapture = container.elements.some(elem => utils_1.PlaceholderUtils.isVariadicCapture(elem));
196
- // If no variadic captures, use parent implementation
197
- if (!hasVariadicCapture) {
198
- return _super.visitContainer.call(this, container, p);
199
- }
200
- // Otherwise, handle variadic captures ourselves
201
- if (!this.match) {
202
- return container;
203
- }
204
- // Extract the other container
205
- const isContainer = p.kind === java_1.J.Kind.Container;
206
- if (!isContainer) {
207
- // Set up cursors temporarily for kindMismatch to use
208
- const savedCursor = this.cursor;
209
- const savedTargetCursor = this.targetCursor;
210
- this.cursor = new __1.Cursor(container, this.cursor);
211
- this.targetCursor = new __1.Cursor(p, this.targetCursor);
212
- try {
213
- return this.kindMismatch();
214
- }
215
- finally {
216
- this.cursor = savedCursor;
217
- this.targetCursor = savedTargetCursor;
218
- }
163
+ finally {
164
+ this.targetCursor = savedTargetCursor;
219
165
  }
220
- const otherContainer = p;
221
- // Push wrappers onto both cursors
166
+ }
167
+ // Not a capture wrapper - use parent implementation
168
+ return super.visitRightPadded(right, p);
169
+ }
170
+ async visitContainer(container, p) {
171
+ // Check if any elements are variadic captures
172
+ const hasVariadicCapture = container.elements.some(elem => utils_1.PlaceholderUtils.isVariadicCapture(elem));
173
+ // If no variadic captures, use parent implementation
174
+ if (!hasVariadicCapture) {
175
+ return super.visitContainer(container, p);
176
+ }
177
+ // Otherwise, handle variadic captures ourselves
178
+ if (!this.match) {
179
+ return container;
180
+ }
181
+ // Extract the other container
182
+ const isContainer = p.kind === java_1.J.Kind.Container;
183
+ if (!isContainer) {
184
+ // Set up cursors temporarily for kindMismatch to use
222
185
  const savedCursor = this.cursor;
223
186
  const savedTargetCursor = this.targetCursor;
224
187
  this.cursor = new __1.Cursor(container, this.cursor);
225
- this.targetCursor = new __1.Cursor(otherContainer, this.targetCursor);
188
+ this.targetCursor = new __1.Cursor(p, this.targetCursor);
226
189
  try {
227
- // Use matchSequence for variadic matching
228
- // filterEmpty=true to skip J.Empty elements (they represent missing elements in destructuring)
229
- if (!(yield this.matchSequence(container.elements, otherContainer.elements, true))) {
230
- return this.structuralMismatch('elements');
231
- }
190
+ return this.kindMismatch();
232
191
  }
233
192
  finally {
234
193
  this.cursor = savedCursor;
235
194
  this.targetCursor = savedTargetCursor;
236
195
  }
237
- return container;
238
- });
196
+ }
197
+ const otherContainer = p;
198
+ // Push wrappers onto both cursors
199
+ const savedCursor = this.cursor;
200
+ const savedTargetCursor = this.targetCursor;
201
+ this.cursor = new __1.Cursor(container, this.cursor);
202
+ this.targetCursor = new __1.Cursor(otherContainer, this.targetCursor);
203
+ try {
204
+ // Use matchSequence for variadic matching
205
+ // filterEmpty=true to skip J.Empty elements (they represent missing elements in destructuring)
206
+ if (!await this.matchSequence(container.elements, otherContainer.elements, true)) {
207
+ return this.structuralMismatch('elements');
208
+ }
209
+ }
210
+ finally {
211
+ this.cursor = savedCursor;
212
+ this.targetCursor = savedTargetCursor;
213
+ }
214
+ return container;
239
215
  }
240
216
  /**
241
217
  * Visit a single element in a container (for non-variadic matching).
@@ -246,200 +222,181 @@ class PatternMatchingComparator extends comparator_1.JavaScriptSemanticComparato
246
222
  * @param index The index in the container
247
223
  * @returns true if matching should continue, false if it failed
248
224
  */
249
- visitContainerElement(element, otherElement, index) {
250
- return __awaiter(this, void 0, void 0, function* () {
251
- yield this.visitRightPadded(element, otherElement);
252
- return this.match;
253
- });
225
+ async visitContainerElement(element, otherElement, index) {
226
+ await this.visitRightPadded(element, otherElement);
227
+ return this.match;
254
228
  }
255
- visitMethodInvocation(methodInvocation, other) {
256
- const _super = Object.create(null, {
257
- visitMethodInvocation: { get: () => super.visitMethodInvocation }
258
- });
259
- return __awaiter(this, void 0, void 0, function* () {
260
- // Check if any arguments are variadic captures
261
- const hasVariadicCapture = methodInvocation.arguments.elements.some(arg => utils_1.PlaceholderUtils.isVariadicCapture(arg));
262
- // If no variadic captures, use parent implementation (which includes semantic/type-aware matching)
263
- if (!hasVariadicCapture) {
264
- return _super.visitMethodInvocation.call(this, methodInvocation, other);
265
- }
266
- // Otherwise, handle variadic captures ourselves
267
- if (!this.match) {
268
- return this.abort(methodInvocation);
269
- }
270
- if (other.kind !== java_1.J.Kind.MethodInvocation) {
271
- // Set up cursors for kindMismatch
272
- const savedCursor = this.cursor;
273
- const savedTargetCursor = this.targetCursor;
274
- this.cursor = new __1.Cursor(methodInvocation, this.cursor);
275
- this.targetCursor = new __1.Cursor(other, this.targetCursor);
276
- try {
277
- return this.kindMismatch();
278
- }
279
- finally {
280
- this.cursor = savedCursor;
281
- this.targetCursor = savedTargetCursor;
282
- }
283
- }
284
- const otherMethodInvocation = other;
285
- // Set up cursors for the entire method
229
+ async visitMethodInvocation(methodInvocation, other) {
230
+ // Check if any arguments are variadic captures
231
+ const hasVariadicCapture = methodInvocation.arguments.elements.some(arg => utils_1.PlaceholderUtils.isVariadicCapture(arg));
232
+ // If no variadic captures, use parent implementation (which includes semantic/type-aware matching)
233
+ if (!hasVariadicCapture) {
234
+ return super.visitMethodInvocation(methodInvocation, other);
235
+ }
236
+ // Otherwise, handle variadic captures ourselves
237
+ if (!this.match) {
238
+ return this.abort(methodInvocation);
239
+ }
240
+ if (other.kind !== java_1.J.Kind.MethodInvocation) {
241
+ // Set up cursors for kindMismatch
286
242
  const savedCursor = this.cursor;
287
243
  const savedTargetCursor = this.targetCursor;
288
244
  this.cursor = new __1.Cursor(methodInvocation, this.cursor);
289
- this.targetCursor = new __1.Cursor(otherMethodInvocation, this.targetCursor);
245
+ this.targetCursor = new __1.Cursor(other, this.targetCursor);
290
246
  try {
291
- // Compare select
292
- if ((methodInvocation.select === undefined) !== (otherMethodInvocation.select === undefined)) {
293
- return this.structuralMismatch('select');
294
- }
295
- // Visit select if present
296
- if (methodInvocation.select && otherMethodInvocation.select) {
297
- yield this.visit(methodInvocation.select.element, otherMethodInvocation.select.element);
298
- if (!this.match)
299
- return methodInvocation;
300
- }
301
- // Compare typeParameters
302
- if ((methodInvocation.typeParameters === undefined) !== (otherMethodInvocation.typeParameters === undefined)) {
303
- return this.structuralMismatch('typeParameters');
304
- }
305
- // Visit typeParameters if present
306
- if (methodInvocation.typeParameters && otherMethodInvocation.typeParameters) {
307
- if (methodInvocation.typeParameters.elements.length !== otherMethodInvocation.typeParameters.elements.length) {
308
- return this.arrayLengthMismatch('typeParameters.elements');
309
- }
310
- // Visit each type parameter in lock step (visit RightPadded to check for markers)
311
- for (let i = 0; i < methodInvocation.typeParameters.elements.length; i++) {
312
- yield this.visitRightPadded(methodInvocation.typeParameters.elements[i], otherMethodInvocation.typeParameters.elements[i]);
313
- if (!this.match)
314
- return methodInvocation;
315
- }
316
- }
317
- // Visit name
318
- yield this.visit(methodInvocation.name, otherMethodInvocation.name);
319
- if (!this.match) {
320
- return methodInvocation;
321
- }
322
- // Special handling for variadic captures in arguments
323
- if (!(yield this.matchArguments(methodInvocation.arguments.elements, otherMethodInvocation.arguments.elements))) {
324
- return this.structuralMismatch('arguments');
325
- }
326
- return methodInvocation;
247
+ return this.kindMismatch();
327
248
  }
328
249
  finally {
329
250
  this.cursor = savedCursor;
330
251
  this.targetCursor = savedTargetCursor;
331
252
  }
332
- });
333
- }
334
- visitBlock(block, other) {
335
- const _super = Object.create(null, {
336
- visitBlock: { get: () => super.visitBlock }
337
- });
338
- return __awaiter(this, void 0, void 0, function* () {
339
- // Check if any statements have CaptureMarker indicating they're variadic
340
- const hasVariadicCapture = block.statements.some(stmt => {
341
- const captureMarker = utils_1.PlaceholderUtils.getCaptureMarker(stmt);
342
- return (captureMarker === null || captureMarker === void 0 ? void 0 : captureMarker.variadicOptions) !== undefined;
343
- });
344
- // If no variadic captures, use parent implementation
345
- if (!hasVariadicCapture) {
346
- return _super.visitBlock.call(this, block, other);
253
+ }
254
+ const otherMethodInvocation = other;
255
+ // Set up cursors for the entire method
256
+ const savedCursor = this.cursor;
257
+ const savedTargetCursor = this.targetCursor;
258
+ this.cursor = new __1.Cursor(methodInvocation, this.cursor);
259
+ this.targetCursor = new __1.Cursor(otherMethodInvocation, this.targetCursor);
260
+ try {
261
+ // Compare select
262
+ if ((methodInvocation.select === undefined) !== (otherMethodInvocation.select === undefined)) {
263
+ return this.structuralMismatch('select');
347
264
  }
348
- // Otherwise, handle variadic captures ourselves
349
- if (!this.match) {
350
- return this.abort(block);
265
+ // Visit select if present
266
+ if (methodInvocation.select && otherMethodInvocation.select) {
267
+ await this.visit(methodInvocation.select.element, otherMethodInvocation.select.element);
268
+ if (!this.match)
269
+ return methodInvocation;
351
270
  }
352
- if (other.kind !== java_1.J.Kind.Block) {
353
- // Set up cursors for kindMismatch
354
- const savedCursor = this.cursor;
355
- const savedTargetCursor = this.targetCursor;
356
- this.cursor = new __1.Cursor(block, this.cursor);
357
- this.targetCursor = new __1.Cursor(other, this.targetCursor);
358
- try {
359
- return this.kindMismatch();
271
+ // Compare typeParameters
272
+ if ((methodInvocation.typeParameters === undefined) !== (otherMethodInvocation.typeParameters === undefined)) {
273
+ return this.structuralMismatch('typeParameters');
274
+ }
275
+ // Visit typeParameters if present
276
+ if (methodInvocation.typeParameters && otherMethodInvocation.typeParameters) {
277
+ if (methodInvocation.typeParameters.elements.length !== otherMethodInvocation.typeParameters.elements.length) {
278
+ return this.arrayLengthMismatch('typeParameters.elements');
360
279
  }
361
- finally {
362
- this.cursor = savedCursor;
363
- this.targetCursor = savedTargetCursor;
280
+ // Visit each type parameter in lock step (visit RightPadded to check for markers)
281
+ for (let i = 0; i < methodInvocation.typeParameters.elements.length; i++) {
282
+ await this.visitRightPadded(methodInvocation.typeParameters.elements[i], otherMethodInvocation.typeParameters.elements[i]);
283
+ if (!this.match)
284
+ return methodInvocation;
364
285
  }
365
286
  }
366
- const otherBlock = other;
367
- // Set up cursors for structural comparison
287
+ // Visit name
288
+ await this.visit(methodInvocation.name, otherMethodInvocation.name);
289
+ if (!this.match) {
290
+ return methodInvocation;
291
+ }
292
+ // Special handling for variadic captures in arguments
293
+ if (!await this.matchArguments(methodInvocation.arguments.elements, otherMethodInvocation.arguments.elements)) {
294
+ return this.structuralMismatch('arguments');
295
+ }
296
+ return methodInvocation;
297
+ }
298
+ finally {
299
+ this.cursor = savedCursor;
300
+ this.targetCursor = savedTargetCursor;
301
+ }
302
+ }
303
+ async visitBlock(block, other) {
304
+ // Check if any statements have CaptureMarker indicating they're variadic
305
+ const hasVariadicCapture = block.statements.some(stmt => {
306
+ const captureMarker = utils_1.PlaceholderUtils.getCaptureMarker(stmt);
307
+ return (captureMarker === null || captureMarker === void 0 ? void 0 : captureMarker.variadicOptions) !== undefined;
308
+ });
309
+ // If no variadic captures, use parent implementation
310
+ if (!hasVariadicCapture) {
311
+ return super.visitBlock(block, other);
312
+ }
313
+ // Otherwise, handle variadic captures ourselves
314
+ if (!this.match) {
315
+ return this.abort(block);
316
+ }
317
+ if (other.kind !== java_1.J.Kind.Block) {
318
+ // Set up cursors for kindMismatch
368
319
  const savedCursor = this.cursor;
369
320
  const savedTargetCursor = this.targetCursor;
370
321
  this.cursor = new __1.Cursor(block, this.cursor);
371
- this.targetCursor = new __1.Cursor(otherBlock, this.targetCursor);
322
+ this.targetCursor = new __1.Cursor(other, this.targetCursor);
372
323
  try {
373
- // Special handling for variadic captures in statements
374
- if (!(yield this.matchSequence(block.statements, otherBlock.statements, false))) {
375
- return this.structuralMismatch('statements');
376
- }
377
- return block;
324
+ return this.kindMismatch();
378
325
  }
379
326
  finally {
380
327
  this.cursor = savedCursor;
381
328
  this.targetCursor = savedTargetCursor;
382
329
  }
383
- });
330
+ }
331
+ const otherBlock = other;
332
+ // Set up cursors for structural comparison
333
+ const savedCursor = this.cursor;
334
+ const savedTargetCursor = this.targetCursor;
335
+ this.cursor = new __1.Cursor(block, this.cursor);
336
+ this.targetCursor = new __1.Cursor(otherBlock, this.targetCursor);
337
+ try {
338
+ // Special handling for variadic captures in statements
339
+ if (!await this.matchSequence(block.statements, otherBlock.statements, false)) {
340
+ return this.structuralMismatch('statements');
341
+ }
342
+ return block;
343
+ }
344
+ finally {
345
+ this.cursor = savedCursor;
346
+ this.targetCursor = savedTargetCursor;
347
+ }
384
348
  }
385
- visitJsCompilationUnit(compilationUnit, other) {
386
- const _super = Object.create(null, {
387
- visitJsCompilationUnit: { get: () => super.visitJsCompilationUnit }
349
+ async visitJsCompilationUnit(compilationUnit, other) {
350
+ // Check if any statements are variadic captures
351
+ const hasVariadicCapture = compilationUnit.statements.some(stmt => {
352
+ return utils_1.PlaceholderUtils.isVariadicCapture(stmt);
388
353
  });
389
- return __awaiter(this, void 0, void 0, function* () {
390
- // Check if any statements are variadic captures
391
- const hasVariadicCapture = compilationUnit.statements.some(stmt => {
392
- return utils_1.PlaceholderUtils.isVariadicCapture(stmt);
393
- });
394
- // If no variadic captures, use parent implementation
395
- if (!hasVariadicCapture) {
396
- return _super.visitJsCompilationUnit.call(this, compilationUnit, other);
397
- }
398
- // Otherwise, handle variadic captures ourselves
399
- if (!this.match) {
400
- return this.abort(compilationUnit);
401
- }
402
- if (other.kind !== index_1.JS.Kind.CompilationUnit) {
403
- // Set up cursors for kindMismatch
404
- const savedCursor = this.cursor;
405
- const savedTargetCursor = this.targetCursor;
406
- this.cursor = new __1.Cursor(compilationUnit, this.cursor);
407
- this.targetCursor = new __1.Cursor(other, this.targetCursor);
408
- try {
409
- return this.kindMismatch();
410
- }
411
- finally {
412
- this.cursor = savedCursor;
413
- this.targetCursor = savedTargetCursor;
414
- }
415
- }
416
- const otherCompilationUnit = other;
417
- // Set up cursors for structural comparison
354
+ // If no variadic captures, use parent implementation
355
+ if (!hasVariadicCapture) {
356
+ return super.visitJsCompilationUnit(compilationUnit, other);
357
+ }
358
+ // Otherwise, handle variadic captures ourselves
359
+ if (!this.match) {
360
+ return this.abort(compilationUnit);
361
+ }
362
+ if (other.kind !== index_1.JS.Kind.CompilationUnit) {
363
+ // Set up cursors for kindMismatch
418
364
  const savedCursor = this.cursor;
419
365
  const savedTargetCursor = this.targetCursor;
420
366
  this.cursor = new __1.Cursor(compilationUnit, this.cursor);
421
- this.targetCursor = new __1.Cursor(otherCompilationUnit, this.targetCursor);
367
+ this.targetCursor = new __1.Cursor(other, this.targetCursor);
422
368
  try {
423
- // Special handling for variadic captures in top-level statements
424
- if (!(yield this.matchSequence(compilationUnit.statements, otherCompilationUnit.statements, false))) {
425
- return this.structuralMismatch('statements');
426
- }
427
- return compilationUnit;
369
+ return this.kindMismatch();
428
370
  }
429
371
  finally {
430
372
  this.cursor = savedCursor;
431
373
  this.targetCursor = savedTargetCursor;
432
374
  }
433
- });
375
+ }
376
+ const otherCompilationUnit = other;
377
+ // Set up cursors for structural comparison
378
+ const savedCursor = this.cursor;
379
+ const savedTargetCursor = this.targetCursor;
380
+ this.cursor = new __1.Cursor(compilationUnit, this.cursor);
381
+ this.targetCursor = new __1.Cursor(otherCompilationUnit, this.targetCursor);
382
+ try {
383
+ // Special handling for variadic captures in top-level statements
384
+ if (!await this.matchSequence(compilationUnit.statements, otherCompilationUnit.statements, false)) {
385
+ return this.structuralMismatch('statements');
386
+ }
387
+ return compilationUnit;
388
+ }
389
+ finally {
390
+ this.cursor = savedCursor;
391
+ this.targetCursor = savedTargetCursor;
392
+ }
434
393
  }
435
394
  /**
436
395
  * Matches argument lists, with special handling for variadic captures.
437
396
  * A variadic capture can match zero or more consecutive arguments.
438
397
  */
439
- matchArguments(patternArgs, targetArgs) {
440
- return __awaiter(this, void 0, void 0, function* () {
441
- return yield this.matchSequence(patternArgs, targetArgs, true);
442
- });
398
+ async matchArguments(patternArgs, targetArgs) {
399
+ return await this.matchSequence(patternArgs, targetArgs, true);
443
400
  }
444
401
  /**
445
402
  * Generic sequence matching with variadic capture support.
@@ -453,10 +410,8 @@ class PatternMatchingComparator extends comparator_1.JavaScriptSemanticComparato
453
410
  * @param filterEmpty Whether to filter out J.Empty elements when capturing (true for arguments, false for statements)
454
411
  * @returns true if the sequence matches, false otherwise
455
412
  */
456
- matchSequence(patternElements, targetElements, filterEmpty) {
457
- return __awaiter(this, void 0, void 0, function* () {
458
- return yield this.matchSequenceOptimized(patternElements, targetElements, 0, 0, filterEmpty);
459
- });
413
+ async matchSequence(patternElements, targetElements, filterEmpty) {
414
+ return await this.matchSequenceOptimized(patternElements, targetElements, 0, 0, filterEmpty);
460
415
  }
461
416
  /**
462
417
  * Optimized sequence matcher with pivot detection and backtracking.
@@ -470,154 +425,152 @@ class PatternMatchingComparator extends comparator_1.JavaScriptSemanticComparato
470
425
  * @param filterEmpty Whether to filter out J.Empty elements when capturing
471
426
  * @returns true if the remaining sequence matches, false otherwise
472
427
  */
473
- matchSequenceOptimized(patternElements, targetElements, patternIdx, targetIdx, filterEmpty) {
474
- return __awaiter(this, void 0, void 0, function* () {
475
- var _a, _b;
476
- // Base case: all patterns matched
477
- if (patternIdx >= patternElements.length) {
478
- return targetIdx >= targetElements.length; // Success if all targets consumed
479
- }
480
- // Check for markers at wrapper level only (markers are now only at the outermost level)
481
- const patternWrapper = patternElements[patternIdx];
482
- const captureMarker = utils_1.PlaceholderUtils.getCaptureMarker(patternWrapper);
483
- const isVariadic = (captureMarker === null || captureMarker === void 0 ? void 0 : captureMarker.variadicOptions) !== undefined;
484
- if (isVariadic) {
485
- // Variadic pattern: try different consumption amounts with backtracking
486
- const variadicOptions = captureMarker.variadicOptions;
487
- const min = (_a = variadicOptions === null || variadicOptions === void 0 ? void 0 : variadicOptions.min) !== null && _a !== void 0 ? _a : 0;
488
- const max = (_b = variadicOptions === null || variadicOptions === void 0 ? void 0 : variadicOptions.max) !== null && _b !== void 0 ? _b : Infinity;
489
- // Calculate maximum possible consumption and check if remaining patterns are deterministic
490
- let nonVariadicRemainingPatterns = 0;
491
- let allRemainingPatternsAreDeterministic = true;
492
- for (let i = patternIdx + 1; i < patternElements.length; i++) {
493
- const nextCaptureMarker = utils_1.PlaceholderUtils.getCaptureMarker(patternElements[i]);
494
- const nextIsVariadic = (nextCaptureMarker === null || nextCaptureMarker === void 0 ? void 0 : nextCaptureMarker.variadicOptions) !== undefined;
495
- if (!nextIsVariadic) {
496
- nonVariadicRemainingPatterns++;
497
- }
498
- // A pattern is deterministic if it's not a capture at all (i.e., a literal/fixed structure)
499
- // Variadic captures and non-variadic captures are both non-deterministic
500
- if (nextCaptureMarker) {
501
- allRemainingPatternsAreDeterministic = false;
502
- }
503
- }
504
- const remainingTargetElements = targetElements.length - targetIdx;
505
- const maxPossible = Math.min(remainingTargetElements - nonVariadicRemainingPatterns, max);
506
- // Pivot detection optimization: try to find where next pattern matches
507
- // This avoids unnecessary backtracking when constraints make the split point obvious
508
- let pivotDetected = false;
509
- let pivotAt = -1;
510
- // Skip pivot detection if we're using deterministic optimization
511
- // (when all remaining patterns are literals, there's only ONE valid consumption amount)
512
- const useDeterministicOptimization = allRemainingPatternsAreDeterministic && maxPossible >= min && maxPossible <= max;
513
- if (!useDeterministicOptimization && patternIdx + 1 < patternElements.length && min <= maxPossible) {
514
- const nextPattern = patternElements[patternIdx + 1];
515
- // Scan through possible consumption amounts starting from min
516
- for (let tryConsume = min; tryConsume <= maxPossible; tryConsume++) {
517
- // Check if element after our consumption would match next pattern
518
- if (targetIdx + tryConsume < targetElements.length) {
519
- const candidateElement = targetElements[targetIdx + tryConsume];
520
- // Skip J.Empty for arguments
521
- if (filterEmpty && candidateElement.element.kind === java_1.J.Kind.Empty) {
522
- continue;
523
- }
524
- // Test if next pattern matches this element
525
- const savedMatch = this.match;
526
- const savedState = this.matcher.saveState();
527
- yield this.visitRightPadded(nextPattern, candidateElement);
528
- const matchesNext = this.match;
529
- this.match = savedMatch;
530
- this.matcher.restoreState(savedState);
531
- if (matchesNext) {
532
- // Found pivot! Try this consumption amount first
533
- pivotDetected = true;
534
- pivotAt = tryConsume;
535
- break;
536
- }
537
- }
538
- }
428
+ async matchSequenceOptimized(patternElements, targetElements, patternIdx, targetIdx, filterEmpty) {
429
+ var _a, _b;
430
+ // Base case: all patterns matched
431
+ if (patternIdx >= patternElements.length) {
432
+ return targetIdx >= targetElements.length; // Success if all targets consumed
433
+ }
434
+ // Check for markers at wrapper level only (markers are now only at the outermost level)
435
+ const patternWrapper = patternElements[patternIdx];
436
+ const captureMarker = utils_1.PlaceholderUtils.getCaptureMarker(patternWrapper);
437
+ const isVariadic = (captureMarker === null || captureMarker === void 0 ? void 0 : captureMarker.variadicOptions) !== undefined;
438
+ if (isVariadic) {
439
+ // Variadic pattern: try different consumption amounts with backtracking
440
+ const variadicOptions = captureMarker.variadicOptions;
441
+ const min = (_a = variadicOptions === null || variadicOptions === void 0 ? void 0 : variadicOptions.min) !== null && _a !== void 0 ? _a : 0;
442
+ const max = (_b = variadicOptions === null || variadicOptions === void 0 ? void 0 : variadicOptions.max) !== null && _b !== void 0 ? _b : Infinity;
443
+ // Calculate maximum possible consumption and check if remaining patterns are deterministic
444
+ let nonVariadicRemainingPatterns = 0;
445
+ let allRemainingPatternsAreDeterministic = true;
446
+ for (let i = patternIdx + 1; i < patternElements.length; i++) {
447
+ const nextCaptureMarker = utils_1.PlaceholderUtils.getCaptureMarker(patternElements[i]);
448
+ const nextIsVariadic = (nextCaptureMarker === null || nextCaptureMarker === void 0 ? void 0 : nextCaptureMarker.variadicOptions) !== undefined;
449
+ if (!nextIsVariadic) {
450
+ nonVariadicRemainingPatterns++;
539
451
  }
540
- // Determine consumption order
541
- const consumptionOrder = [];
542
- // OPTIMIZATION: If all remaining patterns are deterministic (literals, not captures),
543
- // there's only ONE mathematically valid consumption amount. Skip backtracking entirely.
544
- // Example: foo(${args}, 999) matching foo(1,2,42) -> args MUST be [1,2], only try consume=2
545
- if (useDeterministicOptimization) {
546
- consumptionOrder.push(maxPossible);
452
+ // A pattern is deterministic if it's not a capture at all (i.e., a literal/fixed structure)
453
+ // Variadic captures and non-variadic captures are both non-deterministic
454
+ if (nextCaptureMarker) {
455
+ allRemainingPatternsAreDeterministic = false;
547
456
  }
548
- else if (pivotDetected && pivotAt >= 0) {
549
- // Try pivot first, then others as fallback
550
- consumptionOrder.push(pivotAt);
551
- for (let c = maxPossible; c >= min; c--) {
552
- if (c !== pivotAt) {
553
- consumptionOrder.push(c);
457
+ }
458
+ const remainingTargetElements = targetElements.length - targetIdx;
459
+ const maxPossible = Math.min(remainingTargetElements - nonVariadicRemainingPatterns, max);
460
+ // Pivot detection optimization: try to find where next pattern matches
461
+ // This avoids unnecessary backtracking when constraints make the split point obvious
462
+ let pivotDetected = false;
463
+ let pivotAt = -1;
464
+ // Skip pivot detection if we're using deterministic optimization
465
+ // (when all remaining patterns are literals, there's only ONE valid consumption amount)
466
+ const useDeterministicOptimization = allRemainingPatternsAreDeterministic && maxPossible >= min && maxPossible <= max;
467
+ if (!useDeterministicOptimization && patternIdx + 1 < patternElements.length && min <= maxPossible) {
468
+ const nextPattern = patternElements[patternIdx + 1];
469
+ // Scan through possible consumption amounts starting from min
470
+ for (let tryConsume = min; tryConsume <= maxPossible; tryConsume++) {
471
+ // Check if element after our consumption would match next pattern
472
+ if (targetIdx + tryConsume < targetElements.length) {
473
+ const candidateElement = targetElements[targetIdx + tryConsume];
474
+ // Skip J.Empty for arguments
475
+ if (filterEmpty && candidateElement.element.kind === java_1.J.Kind.Empty) {
476
+ continue;
477
+ }
478
+ // Test if next pattern matches this element
479
+ const savedMatch = this.match;
480
+ const savedState = this.matcher.saveState();
481
+ await this.visitRightPadded(nextPattern, candidateElement);
482
+ const matchesNext = this.match;
483
+ this.match = savedMatch;
484
+ this.matcher.restoreState(savedState);
485
+ if (matchesNext) {
486
+ // Found pivot! Try this consumption amount first
487
+ pivotDetected = true;
488
+ pivotAt = tryConsume;
489
+ break;
554
490
  }
555
491
  }
556
492
  }
557
- else {
558
- // Greedy approach: max to min
559
- for (let c = maxPossible; c >= min; c--) {
493
+ }
494
+ // Determine consumption order
495
+ const consumptionOrder = [];
496
+ // OPTIMIZATION: If all remaining patterns are deterministic (literals, not captures),
497
+ // there's only ONE mathematically valid consumption amount. Skip backtracking entirely.
498
+ // Example: foo(${args}, 999) matching foo(1,2,42) -> args MUST be [1,2], only try consume=2
499
+ if (useDeterministicOptimization) {
500
+ consumptionOrder.push(maxPossible);
501
+ }
502
+ else if (pivotDetected && pivotAt >= 0) {
503
+ // Try pivot first, then others as fallback
504
+ consumptionOrder.push(pivotAt);
505
+ for (let c = maxPossible; c >= min; c--) {
506
+ if (c !== pivotAt) {
560
507
  consumptionOrder.push(c);
561
508
  }
562
509
  }
563
- for (const consume of consumptionOrder) {
564
- // Capture elements for this consumption amount
565
- // For empty argument lists, there will be a single J.Empty element that we need to filter out
566
- const rawWrappers = targetElements.slice(targetIdx, targetIdx + consume);
567
- const capturedWrappers = filterEmpty
568
- ? rawWrappers.filter(w => w.element.kind !== java_1.J.Kind.Empty)
569
- : rawWrappers;
570
- const capturedElements = capturedWrappers.map(w => w.element);
571
- // Check min/max constraints against filtered elements
572
- if (capturedElements.length < min || capturedElements.length > max) {
573
- continue;
574
- }
575
- // Evaluate constraint for variadic capture
576
- // For variadic captures, constraint receives the entire array of captured elements
577
- // The targetCursor points to the parent container (always defined in container matching)
578
- if (captureMarker.constraint) {
579
- const cursor = this.targetCursor || new __1.Cursor(targetElements[0]);
580
- if (!captureMarker.constraint(capturedElements, this.buildConstraintContext(cursor))) {
581
- continue; // Try next consumption amount
582
- }
583
- }
584
- // Save current state for backtracking
585
- const savedState = this.matcher.saveState();
586
- // Handle the variadic capture
587
- const success = this.matcher.handleVariadicCapture(captureMarker, capturedElements, capturedWrappers);
588
- if (!success) {
589
- // Restore state and try next amount
590
- this.matcher.restoreState(savedState);
591
- continue;
592
- }
593
- // Try to match the rest of the pattern
594
- const restMatches = yield this.matchSequenceOptimized(patternElements, targetElements, patternIdx + 1, targetIdx + consume, filterEmpty);
595
- if (restMatches) {
596
- return true; // Found a valid matching
597
- }
598
- // Backtrack: restore state and try next amount
599
- this.matcher.restoreState(savedState);
600
- }
601
- return false; // No consumption amount worked
602
510
  }
603
511
  else {
604
- // Regular non-variadic element - must match exactly one target element
605
- if (targetIdx >= targetElements.length) {
606
- return false; // Pattern has more elements than target
512
+ // Greedy approach: max to min
513
+ for (let c = maxPossible; c >= min; c--) {
514
+ consumptionOrder.push(c);
607
515
  }
608
- const targetWrapper = targetElements[targetIdx];
609
- const targetElement = targetWrapper.element;
610
- // For arguments, J.Empty represents no argument, so regular captures should not match it
611
- if (filterEmpty && targetElement.kind === java_1.J.Kind.Empty) {
612
- return false;
516
+ }
517
+ for (const consume of consumptionOrder) {
518
+ // Capture elements for this consumption amount
519
+ // For empty argument lists, there will be a single J.Empty element that we need to filter out
520
+ const rawWrappers = targetElements.slice(targetIdx, targetIdx + consume);
521
+ const capturedWrappers = filterEmpty
522
+ ? rawWrappers.filter(w => w.element.kind !== java_1.J.Kind.Empty)
523
+ : rawWrappers;
524
+ const capturedElements = capturedWrappers.map(w => w.element);
525
+ // Check min/max constraints against filtered elements
526
+ if (capturedElements.length < min || capturedElements.length > max) {
527
+ continue;
528
+ }
529
+ // Evaluate constraint for variadic capture
530
+ // For variadic captures, constraint receives the entire array of captured elements
531
+ // The targetCursor points to the parent container (always defined in container matching)
532
+ if (captureMarker.constraint) {
533
+ const cursor = this.targetCursor || new __1.Cursor(targetElements[0]);
534
+ if (!captureMarker.constraint(capturedElements, this.buildConstraintContext(cursor))) {
535
+ continue; // Try next consumption amount
536
+ }
537
+ }
538
+ // Save current state for backtracking
539
+ const savedState = this.matcher.saveState();
540
+ // Handle the variadic capture
541
+ const success = this.matcher.handleVariadicCapture(captureMarker, capturedElements, capturedWrappers);
542
+ if (!success) {
543
+ // Restore state and try next amount
544
+ this.matcher.restoreState(savedState);
545
+ continue;
613
546
  }
614
- if (!(yield this.visitSequenceElement(patternWrapper, targetWrapper, targetIdx))) {
615
- return false;
547
+ // Try to match the rest of the pattern
548
+ const restMatches = await this.matchSequenceOptimized(patternElements, targetElements, patternIdx + 1, targetIdx + consume, filterEmpty);
549
+ if (restMatches) {
550
+ return true; // Found a valid matching
616
551
  }
617
- // Continue matching the rest
618
- return yield this.matchSequenceOptimized(patternElements, targetElements, patternIdx + 1, targetIdx + 1, filterEmpty);
552
+ // Backtrack: restore state and try next amount
553
+ this.matcher.restoreState(savedState);
619
554
  }
620
- });
555
+ return false; // No consumption amount worked
556
+ }
557
+ else {
558
+ // Regular non-variadic element - must match exactly one target element
559
+ if (targetIdx >= targetElements.length) {
560
+ return false; // Pattern has more elements than target
561
+ }
562
+ const targetWrapper = targetElements[targetIdx];
563
+ const targetElement = targetWrapper.element;
564
+ // For arguments, J.Empty represents no argument, so regular captures should not match it
565
+ if (filterEmpty && targetElement.kind === java_1.J.Kind.Empty) {
566
+ return false;
567
+ }
568
+ if (!await this.visitSequenceElement(patternWrapper, targetWrapper, targetIdx)) {
569
+ return false;
570
+ }
571
+ // Continue matching the rest
572
+ return await this.matchSequenceOptimized(patternElements, targetElements, patternIdx + 1, targetIdx + 1, filterEmpty);
573
+ }
621
574
  }
622
575
  /**
623
576
  * Visit a single element in a sequence during non-variadic matching.
@@ -628,20 +581,18 @@ class PatternMatchingComparator extends comparator_1.JavaScriptSemanticComparato
628
581
  * @param targetIdx The index in the target sequence
629
582
  * @returns true if matching succeeded, false otherwise
630
583
  */
631
- visitSequenceElement(patternWrapper, targetWrapper, targetIdx) {
632
- return __awaiter(this, void 0, void 0, function* () {
633
- // Save current state for backtracking (both match state and capture bindings)
634
- const savedMatch = this.match;
635
- const savedState = this.matcher.saveState();
636
- yield this.visitRightPadded(patternWrapper, targetWrapper);
637
- if (!this.match) {
638
- // Restore state on match failure
639
- this.match = savedMatch;
640
- this.matcher.restoreState(savedState);
641
- return false;
642
- }
643
- return true;
644
- });
584
+ async visitSequenceElement(patternWrapper, targetWrapper, targetIdx) {
585
+ // Save current state for backtracking (both match state and capture bindings)
586
+ const savedMatch = this.match;
587
+ const savedState = this.matcher.saveState();
588
+ await this.visitRightPadded(patternWrapper, targetWrapper);
589
+ if (!this.match) {
590
+ // Restore state on match failure
591
+ this.match = savedMatch;
592
+ this.matcher.restoreState(savedState);
593
+ return false;
594
+ }
595
+ return true;
645
596
  }
646
597
  }
647
598
  exports.PatternMatchingComparator = PatternMatchingComparator;
@@ -789,467 +740,431 @@ class DebugPatternMatchingComparator extends PatternMatchingComparator {
789
740
  }
790
741
  }
791
742
  }
792
- visit(j, p, parent) {
793
- const _super = Object.create(null, {
794
- visit: { get: () => super.visit }
795
- });
796
- return __awaiter(this, void 0, void 0, function* () {
797
- const captureMarker = utils_1.PlaceholderUtils.getCaptureMarker(j);
798
- if (captureMarker) {
799
- const savedTargetCursor = this.targetCursor;
800
- const cursorAtCapturedNode = this.targetCursor !== undefined
801
- ? new __1.Cursor(p, this.targetCursor)
802
- : new __1.Cursor(p);
803
- this.targetCursor = cursorAtCapturedNode;
804
- try {
805
- if (captureMarker.constraint && !captureMarker.variadicOptions) {
806
- this.debug.log('debug', 'constraint', `Evaluating constraint for capture: ${captureMarker.captureName}`);
807
- const constraintResult = captureMarker.constraint(p, this.buildConstraintContext(cursorAtCapturedNode));
808
- if (!constraintResult) {
809
- this.debug.log('info', 'constraint', `Constraint failed for capture: ${captureMarker.captureName}`);
810
- this.debug.setExplanation('constraint-failed', `Capture ${captureMarker.captureName} with valid constraint`, `Constraint failed for ${p.kind}`, `Constraint evaluation returned false`);
811
- return this.abort(j);
812
- }
813
- this.debug.log('debug', 'constraint', `Constraint passed for capture: ${captureMarker.captureName}`);
814
- }
815
- const success = this.matcher.handleCapture(captureMarker, p, undefined);
816
- if (!success) {
743
+ async visit(j, p, parent) {
744
+ const captureMarker = utils_1.PlaceholderUtils.getCaptureMarker(j);
745
+ if (captureMarker) {
746
+ const savedTargetCursor = this.targetCursor;
747
+ const cursorAtCapturedNode = this.targetCursor !== undefined
748
+ ? new __1.Cursor(p, this.targetCursor)
749
+ : new __1.Cursor(p);
750
+ this.targetCursor = cursorAtCapturedNode;
751
+ try {
752
+ if (captureMarker.constraint && !captureMarker.variadicOptions) {
753
+ this.debug.log('debug', 'constraint', `Evaluating constraint for capture: ${captureMarker.captureName}`);
754
+ const constraintResult = captureMarker.constraint(p, this.buildConstraintContext(cursorAtCapturedNode));
755
+ if (!constraintResult) {
756
+ this.debug.log('info', 'constraint', `Constraint failed for capture: ${captureMarker.captureName}`);
757
+ this.debug.setExplanation('constraint-failed', `Capture ${captureMarker.captureName} with valid constraint`, `Constraint failed for ${p.kind}`, `Constraint evaluation returned false`);
817
758
  return this.abort(j);
818
759
  }
819
- return j;
760
+ this.debug.log('debug', 'constraint', `Constraint passed for capture: ${captureMarker.captureName}`);
820
761
  }
821
- finally {
822
- this.targetCursor = savedTargetCursor;
762
+ const success = this.matcher.handleCapture(captureMarker, p, undefined);
763
+ if (!success) {
764
+ return this.abort(j);
823
765
  }
824
- }
825
- return yield _super.visit.call(this, j, p, parent);
826
- });
827
- }
828
- visitElement(j, other) {
829
- return __awaiter(this, void 0, void 0, function* () {
830
- if (!this.match) {
831
766
  return j;
832
767
  }
833
- const kindStr = this.formatKind(j.kind);
834
- if (j.kind !== other.kind) {
835
- return this.abort(j, 'kind-mismatch', 'kind', kindStr, this.formatKind(other.kind));
768
+ finally {
769
+ this.targetCursor = savedTargetCursor;
836
770
  }
837
- for (const key of Object.keys(j)) {
838
- if (key.startsWith('_') || key === 'kind' || key === 'id' || key === 'markers' || key === 'prefix') {
839
- continue;
840
- }
841
- const jValue = j[key];
842
- const otherValue = other[key];
843
- if (Array.isArray(jValue)) {
844
- if (!Array.isArray(otherValue) || jValue.length !== otherValue.length) {
845
- this.debug.pushPath(`${kindStr}#${key}`);
846
- const result = this.abort(j, 'array-length-mismatch', key, jValue.length, Array.isArray(otherValue) ? otherValue.length : otherValue);
847
- this.debug.popPath();
848
- return result;
849
- }
850
- for (let i = 0; i < jValue.length; i++) {
851
- this.debug.pushPath(`${kindStr}#${key}`);
852
- this.debug.pushPath(i.toString());
853
- try {
854
- yield this.visitProperty(jValue[i], otherValue[i]);
855
- if (!this.match) {
856
- return j;
857
- }
858
- }
859
- finally {
860
- this.debug.popPath();
861
- this.debug.popPath();
862
- }
863
- }
771
+ }
772
+ return await super.visit(j, p, parent);
773
+ }
774
+ async visitElement(j, other) {
775
+ if (!this.match) {
776
+ return j;
777
+ }
778
+ const kindStr = this.formatKind(j.kind);
779
+ if (j.kind !== other.kind) {
780
+ return this.abort(j, 'kind-mismatch', 'kind', kindStr, this.formatKind(other.kind));
781
+ }
782
+ for (const key of Object.keys(j)) {
783
+ if (key.startsWith('_') || key === 'kind' || key === 'id' || key === 'markers' || key === 'prefix') {
784
+ continue;
785
+ }
786
+ const jValue = j[key];
787
+ const otherValue = other[key];
788
+ if (Array.isArray(jValue)) {
789
+ if (!Array.isArray(otherValue) || jValue.length !== otherValue.length) {
790
+ this.debug.pushPath(`${kindStr}#${key}`);
791
+ const result = this.abort(j, 'array-length-mismatch', key, jValue.length, Array.isArray(otherValue) ? otherValue.length : otherValue);
792
+ this.debug.popPath();
793
+ return result;
864
794
  }
865
- else {
795
+ for (let i = 0; i < jValue.length; i++) {
866
796
  this.debug.pushPath(`${kindStr}#${key}`);
797
+ this.debug.pushPath(i.toString());
867
798
  try {
868
- yield this.visitProperty(jValue, otherValue);
799
+ await this.visitProperty(jValue[i], otherValue[i]);
869
800
  if (!this.match) {
870
801
  return j;
871
802
  }
872
803
  }
873
804
  finally {
874
805
  this.debug.popPath();
806
+ this.debug.popPath();
875
807
  }
876
808
  }
877
809
  }
878
- return j;
879
- });
880
- }
881
- visitRightPadded(right, p) {
882
- const _super = Object.create(null, {
883
- visitRightPadded: { get: () => super.visitRightPadded }
884
- });
885
- return __awaiter(this, void 0, void 0, function* () {
886
- if (!this.match) {
887
- return right;
888
- }
889
- const captureMarker = utils_1.PlaceholderUtils.getCaptureMarker(right);
890
- if (captureMarker) {
891
- const isRightPadded = p.kind === java_1.J.Kind.RightPadded;
892
- const targetWrapper = isRightPadded ? p : undefined;
893
- const targetElement = isRightPadded ? targetWrapper.element : p;
894
- const savedTargetCursor = this.targetCursor;
895
- const cursorAtCapturedNode = this.targetCursor !== undefined
896
- ? (targetWrapper ? new __1.Cursor(targetWrapper, this.targetCursor) : new __1.Cursor(targetElement, this.targetCursor))
897
- : (targetWrapper ? new __1.Cursor(targetWrapper) : new __1.Cursor(targetElement));
898
- this.targetCursor = cursorAtCapturedNode;
810
+ else {
811
+ this.debug.pushPath(`${kindStr}#${key}`);
899
812
  try {
900
- if (captureMarker.constraint && !captureMarker.variadicOptions) {
901
- this.debug.log('debug', 'constraint', `Evaluating constraint for wrapped capture: ${captureMarker.captureName}`);
902
- const constraintResult = captureMarker.constraint(targetElement, this.buildConstraintContext(cursorAtCapturedNode));
903
- if (!constraintResult) {
904
- this.debug.log('info', 'constraint', `Constraint failed for wrapped capture: ${captureMarker.captureName}`);
905
- this.debug.setExplanation('constraint-failed', `Capture ${captureMarker.captureName} with valid constraint`, `Constraint failed for ${targetElement.kind}`, `Constraint evaluation returned false`);
906
- return this.abort(right);
907
- }
908
- this.debug.log('debug', 'constraint', `Constraint passed for wrapped capture: ${captureMarker.captureName}`);
813
+ await this.visitProperty(jValue, otherValue);
814
+ if (!this.match) {
815
+ return j;
909
816
  }
910
- const success = this.matcher.handleCapture(captureMarker, targetElement, targetWrapper);
911
- if (!success) {
912
- return this.abort(right);
913
- }
914
- return right;
915
817
  }
916
818
  finally {
917
- this.targetCursor = savedTargetCursor;
819
+ this.debug.popPath();
918
820
  }
919
821
  }
920
- return yield _super.visitRightPadded.call(this, right, p);
921
- });
822
+ }
823
+ return j;
922
824
  }
923
- visitContainer(container, p) {
924
- return __awaiter(this, void 0, void 0, function* () {
925
- if (!this.match) {
926
- return container;
927
- }
928
- const isContainer = p.kind === java_1.J.Kind.Container;
929
- if (!isContainer) {
930
- return this.abort(container);
931
- }
932
- const otherContainer = p;
933
- const hasVariadicCapture = container.elements.some(elem => utils_1.PlaceholderUtils.isVariadicCapture(elem));
934
- const savedCursor = this.cursor;
825
+ async visitRightPadded(right, p) {
826
+ if (!this.match) {
827
+ return right;
828
+ }
829
+ const captureMarker = utils_1.PlaceholderUtils.getCaptureMarker(right);
830
+ if (captureMarker) {
831
+ const isRightPadded = p.kind === java_1.J.Kind.RightPadded;
832
+ const targetWrapper = isRightPadded ? p : undefined;
833
+ const targetElement = isRightPadded ? targetWrapper.element : p;
935
834
  const savedTargetCursor = this.targetCursor;
936
- this.cursor = new __1.Cursor(container, this.cursor);
937
- this.targetCursor = new __1.Cursor(otherContainer, this.targetCursor);
835
+ const cursorAtCapturedNode = this.targetCursor !== undefined
836
+ ? (targetWrapper ? new __1.Cursor(targetWrapper, this.targetCursor) : new __1.Cursor(targetElement, this.targetCursor))
837
+ : (targetWrapper ? new __1.Cursor(targetWrapper) : new __1.Cursor(targetElement));
838
+ this.targetCursor = cursorAtCapturedNode;
938
839
  try {
939
- if (hasVariadicCapture) {
940
- if (!(yield this.matchSequence(container.elements, otherContainer.elements, true))) {
941
- return this.arrayLengthMismatch('elements');
840
+ if (captureMarker.constraint && !captureMarker.variadicOptions) {
841
+ this.debug.log('debug', 'constraint', `Evaluating constraint for wrapped capture: ${captureMarker.captureName}`);
842
+ const constraintResult = captureMarker.constraint(targetElement, this.buildConstraintContext(cursorAtCapturedNode));
843
+ if (!constraintResult) {
844
+ this.debug.log('info', 'constraint', `Constraint failed for wrapped capture: ${captureMarker.captureName}`);
845
+ this.debug.setExplanation('constraint-failed', `Capture ${captureMarker.captureName} with valid constraint`, `Constraint failed for ${targetElement.kind}`, `Constraint evaluation returned false`);
846
+ return this.abort(right);
942
847
  }
848
+ this.debug.log('debug', 'constraint', `Constraint passed for wrapped capture: ${captureMarker.captureName}`);
943
849
  }
944
- else {
945
- // Non-variadic path - track indices
946
- if (container.elements.length !== otherContainer.elements.length) {
947
- return this.arrayLengthMismatch('elements');
948
- }
949
- for (let i = 0; i < container.elements.length; i++) {
950
- this.debug.pushPath(i.toString());
951
- try {
952
- if (!(yield this.visitContainerElement(container.elements[i], otherContainer.elements[i], i))) {
953
- return container;
954
- }
955
- }
956
- finally {
957
- this.debug.popPath();
958
- }
959
- }
850
+ const success = this.matcher.handleCapture(captureMarker, targetElement, targetWrapper);
851
+ if (!success) {
852
+ return this.abort(right);
960
853
  }
854
+ return right;
961
855
  }
962
856
  finally {
963
- this.cursor = savedCursor;
964
857
  this.targetCursor = savedTargetCursor;
965
858
  }
859
+ }
860
+ return await super.visitRightPadded(right, p);
861
+ }
862
+ async visitContainer(container, p) {
863
+ if (!this.match) {
966
864
  return container;
967
- });
865
+ }
866
+ const isContainer = p.kind === java_1.J.Kind.Container;
867
+ if (!isContainer) {
868
+ return this.abort(container);
869
+ }
870
+ const otherContainer = p;
871
+ const hasVariadicCapture = container.elements.some(elem => utils_1.PlaceholderUtils.isVariadicCapture(elem));
872
+ const savedCursor = this.cursor;
873
+ const savedTargetCursor = this.targetCursor;
874
+ this.cursor = new __1.Cursor(container, this.cursor);
875
+ this.targetCursor = new __1.Cursor(otherContainer, this.targetCursor);
876
+ try {
877
+ if (hasVariadicCapture) {
878
+ if (!await this.matchSequence(container.elements, otherContainer.elements, true)) {
879
+ return this.arrayLengthMismatch('elements');
880
+ }
881
+ }
882
+ else {
883
+ // Non-variadic path - track indices
884
+ if (container.elements.length !== otherContainer.elements.length) {
885
+ return this.arrayLengthMismatch('elements');
886
+ }
887
+ for (let i = 0; i < container.elements.length; i++) {
888
+ this.debug.pushPath(i.toString());
889
+ try {
890
+ if (!await this.visitContainerElement(container.elements[i], otherContainer.elements[i], i)) {
891
+ return container;
892
+ }
893
+ }
894
+ finally {
895
+ this.debug.popPath();
896
+ }
897
+ }
898
+ }
899
+ }
900
+ finally {
901
+ this.cursor = savedCursor;
902
+ this.targetCursor = savedTargetCursor;
903
+ }
904
+ return container;
968
905
  }
969
906
  /**
970
907
  * Override visitContainerProperty to add path tracking with property context.
971
908
  */
972
- visitContainerProperty(propertyName, container, otherContainer) {
973
- return __awaiter(this, void 0, void 0, function* () {
974
- // Get parent from cursor
975
- const parent = this.cursor.value;
976
- // Push path for the property
977
- const kindStr = this.formatKind(parent.kind);
978
- this.debug.pushPath(`${kindStr}#${propertyName}`);
979
- try {
980
- yield this.visitContainer(container, otherContainer);
981
- return container;
982
- }
983
- finally {
984
- this.debug.popPath();
985
- }
986
- });
909
+ async visitContainerProperty(propertyName, container, otherContainer) {
910
+ // Get parent from cursor
911
+ const parent = this.cursor.value;
912
+ // Push path for the property
913
+ const kindStr = this.formatKind(parent.kind);
914
+ this.debug.pushPath(`${kindStr}#${propertyName}`);
915
+ try {
916
+ await this.visitContainer(container, otherContainer);
917
+ return container;
918
+ }
919
+ finally {
920
+ this.debug.popPath();
921
+ }
987
922
  }
988
923
  /**
989
924
  * Override visitRightPaddedProperty to add path tracking with property context.
990
925
  */
991
- visitRightPaddedProperty(propertyName, rightPadded, otherRightPadded) {
992
- return __awaiter(this, void 0, void 0, function* () {
993
- // Get parent from cursor
994
- const parent = this.cursor.value;
995
- // Push path for the property
996
- const kindStr = this.formatKind(parent.kind);
997
- this.debug.pushPath(`${kindStr}#${propertyName}`);
998
- try {
999
- return yield this.visitRightPadded(rightPadded, otherRightPadded);
1000
- }
1001
- finally {
1002
- this.debug.popPath();
1003
- }
1004
- });
926
+ async visitRightPaddedProperty(propertyName, rightPadded, otherRightPadded) {
927
+ // Get parent from cursor
928
+ const parent = this.cursor.value;
929
+ // Push path for the property
930
+ const kindStr = this.formatKind(parent.kind);
931
+ this.debug.pushPath(`${kindStr}#${propertyName}`);
932
+ try {
933
+ return await this.visitRightPadded(rightPadded, otherRightPadded);
934
+ }
935
+ finally {
936
+ this.debug.popPath();
937
+ }
1005
938
  }
1006
939
  /**
1007
940
  * Override visitLeftPaddedProperty to add path tracking with property context.
1008
941
  */
1009
- visitLeftPaddedProperty(propertyName, leftPadded, otherLeftPadded) {
1010
- return __awaiter(this, void 0, void 0, function* () {
1011
- // Get parent from cursor
1012
- const parent = this.cursor.value;
1013
- // Push path for the property
1014
- const kindStr = this.formatKind(parent.kind);
1015
- this.debug.pushPath(`${kindStr}#${propertyName}`);
1016
- try {
1017
- return yield this.visitLeftPadded(leftPadded, otherLeftPadded);
1018
- }
1019
- finally {
1020
- this.debug.popPath();
1021
- }
1022
- });
942
+ async visitLeftPaddedProperty(propertyName, leftPadded, otherLeftPadded) {
943
+ // Get parent from cursor
944
+ const parent = this.cursor.value;
945
+ // Push path for the property
946
+ const kindStr = this.formatKind(parent.kind);
947
+ this.debug.pushPath(`${kindStr}#${propertyName}`);
948
+ try {
949
+ return await this.visitLeftPadded(leftPadded, otherLeftPadded);
950
+ }
951
+ finally {
952
+ this.debug.popPath();
953
+ }
1023
954
  }
1024
- visitContainerElement(element, otherElement, index) {
1025
- const _super = Object.create(null, {
1026
- visitContainerElement: { get: () => super.visitContainerElement }
1027
- });
1028
- return __awaiter(this, void 0, void 0, function* () {
1029
- // Don't push index here - it should be handled by the caller with proper context
1030
- return yield _super.visitContainerElement.call(this, element, otherElement, index);
1031
- });
955
+ async visitContainerElement(element, otherElement, index) {
956
+ // Don't push index here - it should be handled by the caller with proper context
957
+ return await super.visitContainerElement(element, otherElement, index);
1032
958
  }
1033
- visitArrayProperty(parent, propertyName, array1, array2, visitor) {
1034
- return __awaiter(this, void 0, void 0, function* () {
1035
- // Push path for the property
1036
- const kindStr = this.formatKind(parent.kind);
1037
- this.debug.pushPath(`${kindStr}#${propertyName}`);
1038
- try {
1039
- // Check length mismatch (will have path context)
1040
- if (array1.length !== array2.length) {
1041
- this.arrayLengthMismatch(propertyName);
1042
- return;
1043
- }
1044
- // Visit each element with index tracking
1045
- for (let i = 0; i < array1.length; i++) {
1046
- this.debug.pushPath(i.toString());
1047
- try {
1048
- yield visitor(array1[i], array2[i], i);
1049
- if (!this.match) {
1050
- return;
1051
- }
1052
- }
1053
- finally {
1054
- this.debug.popPath();
1055
- }
1056
- }
1057
- }
1058
- finally {
1059
- this.debug.popPath();
959
+ async visitArrayProperty(parent, propertyName, array1, array2, visitor) {
960
+ // Push path for the property
961
+ const kindStr = this.formatKind(parent.kind);
962
+ this.debug.pushPath(`${kindStr}#${propertyName}`);
963
+ try {
964
+ // Check length mismatch (will have path context)
965
+ if (array1.length !== array2.length) {
966
+ this.arrayLengthMismatch(propertyName);
967
+ return;
1060
968
  }
1061
- });
1062
- }
1063
- matchSequence(patternElements, targetElements, filterEmpty) {
1064
- const _super = Object.create(null, {
1065
- matchSequence: { get: () => super.matchSequence }
1066
- });
1067
- return __awaiter(this, void 0, void 0, function* () {
1068
- var _a, _b;
1069
- // Push path component for the container
1070
- // Extract kind from cursors if available
1071
- const pattern = (_a = this.cursor) === null || _a === void 0 ? void 0 : _a.value;
1072
- if (pattern && pattern.kind) {
1073
- const kindStr = this.formatKind(pattern.kind);
1074
- // Determine property name based on the kind
1075
- let propertyName = 'elements';
1076
- if (pattern.kind.includes('MethodInvocation')) {
1077
- propertyName = 'arguments';
1078
- }
1079
- else if (pattern.kind.includes('Block')) {
1080
- propertyName = 'statements';
969
+ // Visit each element with index tracking
970
+ for (let i = 0; i < array1.length; i++) {
971
+ this.debug.pushPath(i.toString());
972
+ try {
973
+ await visitor(array1[i], array2[i], i);
974
+ if (!this.match) {
975
+ return;
976
+ }
1081
977
  }
1082
- this.debug.pushPath(`${kindStr}#${propertyName}`);
1083
- }
1084
- try {
1085
- return yield _super.matchSequence.call(this, patternElements, targetElements, filterEmpty);
1086
- }
1087
- finally {
1088
- if ((_b = this.cursor) === null || _b === void 0 ? void 0 : _b.value) {
978
+ finally {
1089
979
  this.debug.popPath();
1090
980
  }
1091
981
  }
1092
- });
982
+ }
983
+ finally {
984
+ this.debug.popPath();
985
+ }
1093
986
  }
1094
- visitSequenceElement(patternWrapper, targetWrapper, targetIdx) {
1095
- return __awaiter(this, void 0, void 0, function* () {
1096
- this.debug.pushPath(targetIdx.toString());
1097
- try {
1098
- // Save current state for backtracking (both match state and capture bindings)
1099
- const savedMatch = this.match;
1100
- const savedState = this.matcher.saveState();
1101
- yield this.visitRightPadded(patternWrapper, targetWrapper);
1102
- if (!this.match) {
1103
- // Preserve explanation before restoring state
1104
- const explanation = this.debug.getExplanation();
1105
- // Restore state on match failure
1106
- this.match = savedMatch;
1107
- this.matcher.restoreState(savedState);
1108
- // Restore the explanation if one was set during matching
1109
- if (explanation) {
1110
- this.debug.restoreExplanation(explanation);
1111
- }
1112
- return false;
1113
- }
1114
- return true;
987
+ async matchSequence(patternElements, targetElements, filterEmpty) {
988
+ var _a, _b;
989
+ // Push path component for the container
990
+ // Extract kind from cursors if available
991
+ const pattern = (_a = this.cursor) === null || _a === void 0 ? void 0 : _a.value;
992
+ if (pattern && pattern.kind) {
993
+ const kindStr = this.formatKind(pattern.kind);
994
+ // Determine property name based on the kind
995
+ let propertyName = 'elements';
996
+ if (pattern.kind.includes('MethodInvocation')) {
997
+ propertyName = 'arguments';
1115
998
  }
1116
- finally {
999
+ else if (pattern.kind.includes('Block')) {
1000
+ propertyName = 'statements';
1001
+ }
1002
+ this.debug.pushPath(`${kindStr}#${propertyName}`);
1003
+ }
1004
+ try {
1005
+ return await super.matchSequence(patternElements, targetElements, filterEmpty);
1006
+ }
1007
+ finally {
1008
+ if ((_b = this.cursor) === null || _b === void 0 ? void 0 : _b.value) {
1117
1009
  this.debug.popPath();
1118
1010
  }
1119
- });
1011
+ }
1120
1012
  }
1121
- matchSequenceOptimized(patternElements, targetElements, patternIdx, targetIdx, filterEmpty) {
1122
- return __awaiter(this, void 0, void 0, function* () {
1123
- var _a, _b;
1124
- if (patternIdx >= patternElements.length) {
1125
- return targetIdx >= targetElements.length;
1126
- }
1127
- const patternWrapper = patternElements[patternIdx];
1128
- const captureMarker = utils_1.PlaceholderUtils.getCaptureMarker(patternWrapper);
1129
- const isVariadic = (captureMarker === null || captureMarker === void 0 ? void 0 : captureMarker.variadicOptions) !== undefined;
1130
- if (isVariadic) {
1131
- const variadicOptions = captureMarker.variadicOptions;
1132
- const min = (_a = variadicOptions === null || variadicOptions === void 0 ? void 0 : variadicOptions.min) !== null && _a !== void 0 ? _a : 0;
1133
- const max = (_b = variadicOptions === null || variadicOptions === void 0 ? void 0 : variadicOptions.max) !== null && _b !== void 0 ? _b : Infinity;
1134
- let nonVariadicRemainingPatterns = 0;
1135
- let allRemainingPatternsAreDeterministic = true;
1136
- for (let i = patternIdx + 1; i < patternElements.length; i++) {
1137
- const nextCaptureMarker = utils_1.PlaceholderUtils.getCaptureMarker(patternElements[i]);
1138
- const nextIsVariadic = (nextCaptureMarker === null || nextCaptureMarker === void 0 ? void 0 : nextCaptureMarker.variadicOptions) !== undefined;
1139
- if (!nextIsVariadic) {
1140
- nonVariadicRemainingPatterns++;
1141
- }
1142
- if (nextCaptureMarker) {
1143
- allRemainingPatternsAreDeterministic = false;
1144
- }
1013
+ async visitSequenceElement(patternWrapper, targetWrapper, targetIdx) {
1014
+ this.debug.pushPath(targetIdx.toString());
1015
+ try {
1016
+ // Save current state for backtracking (both match state and capture bindings)
1017
+ const savedMatch = this.match;
1018
+ const savedState = this.matcher.saveState();
1019
+ await this.visitRightPadded(patternWrapper, targetWrapper);
1020
+ if (!this.match) {
1021
+ // Preserve explanation before restoring state
1022
+ const explanation = this.debug.getExplanation();
1023
+ // Restore state on match failure
1024
+ this.match = savedMatch;
1025
+ this.matcher.restoreState(savedState);
1026
+ // Restore the explanation if one was set during matching
1027
+ if (explanation) {
1028
+ this.debug.restoreExplanation(explanation);
1145
1029
  }
1146
- const remainingTargetElements = targetElements.length - targetIdx;
1147
- const maxPossible = Math.min(remainingTargetElements - nonVariadicRemainingPatterns, max);
1148
- let pivotDetected = false;
1149
- let pivotAt = -1;
1150
- // Skip pivot detection if we're using deterministic optimization
1151
- // (when all remaining patterns are literals, there's only ONE valid consumption amount)
1152
- const useDeterministicOptimization = allRemainingPatternsAreDeterministic && maxPossible >= min && maxPossible <= max;
1153
- if (!useDeterministicOptimization && patternIdx + 1 < patternElements.length && min <= maxPossible) {
1154
- const nextPattern = patternElements[patternIdx + 1];
1155
- for (let tryConsume = min; tryConsume <= maxPossible; tryConsume++) {
1156
- if (targetIdx + tryConsume < targetElements.length) {
1157
- const candidateElement = targetElements[targetIdx + tryConsume];
1158
- if (filterEmpty && candidateElement.element.kind === java_1.J.Kind.Empty) {
1159
- continue;
1160
- }
1161
- const savedMatch = this.match;
1162
- const savedState = this.matcher.saveState();
1163
- yield this.visitRightPadded(nextPattern, candidateElement);
1164
- const matchesNext = this.match;
1165
- this.match = savedMatch;
1166
- this.matcher.restoreState(savedState);
1167
- if (matchesNext) {
1168
- pivotDetected = true;
1169
- pivotAt = tryConsume;
1170
- break;
1171
- }
1172
- }
1173
- }
1030
+ return false;
1031
+ }
1032
+ return true;
1033
+ }
1034
+ finally {
1035
+ this.debug.popPath();
1036
+ }
1037
+ }
1038
+ async matchSequenceOptimized(patternElements, targetElements, patternIdx, targetIdx, filterEmpty) {
1039
+ var _a, _b;
1040
+ if (patternIdx >= patternElements.length) {
1041
+ return targetIdx >= targetElements.length;
1042
+ }
1043
+ const patternWrapper = patternElements[patternIdx];
1044
+ const captureMarker = utils_1.PlaceholderUtils.getCaptureMarker(patternWrapper);
1045
+ const isVariadic = (captureMarker === null || captureMarker === void 0 ? void 0 : captureMarker.variadicOptions) !== undefined;
1046
+ if (isVariadic) {
1047
+ const variadicOptions = captureMarker.variadicOptions;
1048
+ const min = (_a = variadicOptions === null || variadicOptions === void 0 ? void 0 : variadicOptions.min) !== null && _a !== void 0 ? _a : 0;
1049
+ const max = (_b = variadicOptions === null || variadicOptions === void 0 ? void 0 : variadicOptions.max) !== null && _b !== void 0 ? _b : Infinity;
1050
+ let nonVariadicRemainingPatterns = 0;
1051
+ let allRemainingPatternsAreDeterministic = true;
1052
+ for (let i = patternIdx + 1; i < patternElements.length; i++) {
1053
+ const nextCaptureMarker = utils_1.PlaceholderUtils.getCaptureMarker(patternElements[i]);
1054
+ const nextIsVariadic = (nextCaptureMarker === null || nextCaptureMarker === void 0 ? void 0 : nextCaptureMarker.variadicOptions) !== undefined;
1055
+ if (!nextIsVariadic) {
1056
+ nonVariadicRemainingPatterns++;
1174
1057
  }
1175
- const consumptionOrder = [];
1176
- // OPTIMIZATION: If all remaining patterns are deterministic (literals, not captures),
1177
- // there's only ONE mathematically valid consumption amount. Skip backtracking entirely.
1178
- // Example: foo(${args}, 999) matching foo(1,2,42) -> args MUST be [1,2], only try consume=2
1179
- if (useDeterministicOptimization) {
1180
- consumptionOrder.push(maxPossible);
1058
+ if (nextCaptureMarker) {
1059
+ allRemainingPatternsAreDeterministic = false;
1181
1060
  }
1182
- else if (pivotDetected && pivotAt >= 0) {
1183
- consumptionOrder.push(pivotAt);
1184
- for (let c = maxPossible; c >= min; c--) {
1185
- if (c !== pivotAt) {
1186
- consumptionOrder.push(c);
1061
+ }
1062
+ const remainingTargetElements = targetElements.length - targetIdx;
1063
+ const maxPossible = Math.min(remainingTargetElements - nonVariadicRemainingPatterns, max);
1064
+ let pivotDetected = false;
1065
+ let pivotAt = -1;
1066
+ // Skip pivot detection if we're using deterministic optimization
1067
+ // (when all remaining patterns are literals, there's only ONE valid consumption amount)
1068
+ const useDeterministicOptimization = allRemainingPatternsAreDeterministic && maxPossible >= min && maxPossible <= max;
1069
+ if (!useDeterministicOptimization && patternIdx + 1 < patternElements.length && min <= maxPossible) {
1070
+ const nextPattern = patternElements[patternIdx + 1];
1071
+ for (let tryConsume = min; tryConsume <= maxPossible; tryConsume++) {
1072
+ if (targetIdx + tryConsume < targetElements.length) {
1073
+ const candidateElement = targetElements[targetIdx + tryConsume];
1074
+ if (filterEmpty && candidateElement.element.kind === java_1.J.Kind.Empty) {
1075
+ continue;
1076
+ }
1077
+ const savedMatch = this.match;
1078
+ const savedState = this.matcher.saveState();
1079
+ await this.visitRightPadded(nextPattern, candidateElement);
1080
+ const matchesNext = this.match;
1081
+ this.match = savedMatch;
1082
+ this.matcher.restoreState(savedState);
1083
+ if (matchesNext) {
1084
+ pivotDetected = true;
1085
+ pivotAt = tryConsume;
1086
+ break;
1187
1087
  }
1188
1088
  }
1189
1089
  }
1190
- else {
1191
- for (let c = maxPossible; c >= min; c--) {
1090
+ }
1091
+ const consumptionOrder = [];
1092
+ // OPTIMIZATION: If all remaining patterns are deterministic (literals, not captures),
1093
+ // there's only ONE mathematically valid consumption amount. Skip backtracking entirely.
1094
+ // Example: foo(${args}, 999) matching foo(1,2,42) -> args MUST be [1,2], only try consume=2
1095
+ if (useDeterministicOptimization) {
1096
+ consumptionOrder.push(maxPossible);
1097
+ }
1098
+ else if (pivotDetected && pivotAt >= 0) {
1099
+ consumptionOrder.push(pivotAt);
1100
+ for (let c = maxPossible; c >= min; c--) {
1101
+ if (c !== pivotAt) {
1192
1102
  consumptionOrder.push(c);
1193
1103
  }
1194
1104
  }
1195
- for (const consume of consumptionOrder) {
1196
- // Capture elements for this consumption amount
1197
- // For empty argument lists, there will be a single J.Empty element that we need to filter out
1198
- const rawWrappers = targetElements.slice(targetIdx, targetIdx + consume);
1199
- const capturedWrappers = filterEmpty
1200
- ? rawWrappers.filter(w => w.element.kind !== java_1.J.Kind.Empty)
1201
- : rawWrappers;
1202
- const capturedElements = capturedWrappers.map(w => w.element);
1203
- // Check min/max constraints against filtered elements
1204
- if (capturedElements.length < min || capturedElements.length > max) {
1205
- continue;
1206
- }
1207
- if (captureMarker.constraint) {
1208
- this.debug.log('debug', 'constraint', `Evaluating variadic constraint for capture: ${captureMarker.captureName} (${capturedElements.length} elements)`);
1209
- const cursor = this.targetCursor || new __1.Cursor(targetElements[0]);
1210
- const constraintResult = captureMarker.constraint(capturedElements, this.buildConstraintContext(cursor));
1211
- if (!constraintResult) {
1212
- this.debug.log('info', 'constraint', `Variadic constraint failed for capture: ${captureMarker.captureName}`);
1213
- continue;
1214
- }
1215
- this.debug.log('debug', 'constraint', `Variadic constraint passed for capture: ${captureMarker.captureName}`);
1216
- }
1217
- const savedState = this.matcher.saveState();
1218
- const success = this.matcher.handleVariadicCapture(captureMarker, capturedElements, capturedWrappers);
1219
- if (!success) {
1220
- this.matcher.restoreState(savedState);
1105
+ }
1106
+ else {
1107
+ for (let c = maxPossible; c >= min; c--) {
1108
+ consumptionOrder.push(c);
1109
+ }
1110
+ }
1111
+ for (const consume of consumptionOrder) {
1112
+ // Capture elements for this consumption amount
1113
+ // For empty argument lists, there will be a single J.Empty element that we need to filter out
1114
+ const rawWrappers = targetElements.slice(targetIdx, targetIdx + consume);
1115
+ const capturedWrappers = filterEmpty
1116
+ ? rawWrappers.filter(w => w.element.kind !== java_1.J.Kind.Empty)
1117
+ : rawWrappers;
1118
+ const capturedElements = capturedWrappers.map(w => w.element);
1119
+ // Check min/max constraints against filtered elements
1120
+ if (capturedElements.length < min || capturedElements.length > max) {
1121
+ continue;
1122
+ }
1123
+ if (captureMarker.constraint) {
1124
+ this.debug.log('debug', 'constraint', `Evaluating variadic constraint for capture: ${captureMarker.captureName} (${capturedElements.length} elements)`);
1125
+ const cursor = this.targetCursor || new __1.Cursor(targetElements[0]);
1126
+ const constraintResult = captureMarker.constraint(capturedElements, this.buildConstraintContext(cursor));
1127
+ if (!constraintResult) {
1128
+ this.debug.log('info', 'constraint', `Variadic constraint failed for capture: ${captureMarker.captureName}`);
1221
1129
  continue;
1222
1130
  }
1223
- const restMatches = yield this.matchSequenceOptimized(patternElements, targetElements, patternIdx + 1, targetIdx + consume, filterEmpty);
1224
- if (restMatches) {
1225
- return true;
1226
- }
1227
- // Preserve explanation from this failed attempt before restoring state
1228
- // This is especially important when using deterministic optimization (only one attempt)
1229
- const currentExplanation = this.debug.getExplanation();
1230
- this.matcher.restoreState(savedState);
1231
- // Restore the explanation if one was set during this attempt
1232
- if (currentExplanation) {
1233
- this.debug.restoreExplanation(currentExplanation);
1234
- }
1131
+ this.debug.log('debug', 'constraint', `Variadic constraint passed for capture: ${captureMarker.captureName}`);
1235
1132
  }
1236
- return false;
1237
- }
1238
- else {
1239
- if (targetIdx >= targetElements.length) {
1240
- return false;
1133
+ const savedState = this.matcher.saveState();
1134
+ const success = this.matcher.handleVariadicCapture(captureMarker, capturedElements, capturedWrappers);
1135
+ if (!success) {
1136
+ this.matcher.restoreState(savedState);
1137
+ continue;
1241
1138
  }
1242
- const targetWrapper = targetElements[targetIdx];
1243
- const targetElement = targetWrapper.element;
1244
- if (filterEmpty && targetElement.kind === java_1.J.Kind.Empty) {
1245
- return false;
1139
+ const restMatches = await this.matchSequenceOptimized(patternElements, targetElements, patternIdx + 1, targetIdx + consume, filterEmpty);
1140
+ if (restMatches) {
1141
+ return true;
1246
1142
  }
1247
- if (!(yield this.visitSequenceElement(patternWrapper, targetWrapper, targetIdx))) {
1248
- return false;
1143
+ // Preserve explanation from this failed attempt before restoring state
1144
+ // This is especially important when using deterministic optimization (only one attempt)
1145
+ const currentExplanation = this.debug.getExplanation();
1146
+ this.matcher.restoreState(savedState);
1147
+ // Restore the explanation if one was set during this attempt
1148
+ if (currentExplanation) {
1149
+ this.debug.restoreExplanation(currentExplanation);
1249
1150
  }
1250
- return yield this.matchSequenceOptimized(patternElements, targetElements, patternIdx + 1, targetIdx + 1, filterEmpty);
1251
1151
  }
1252
- });
1152
+ return false;
1153
+ }
1154
+ else {
1155
+ if (targetIdx >= targetElements.length) {
1156
+ return false;
1157
+ }
1158
+ const targetWrapper = targetElements[targetIdx];
1159
+ const targetElement = targetWrapper.element;
1160
+ if (filterEmpty && targetElement.kind === java_1.J.Kind.Empty) {
1161
+ return false;
1162
+ }
1163
+ if (!await this.visitSequenceElement(patternWrapper, targetWrapper, targetIdx)) {
1164
+ return false;
1165
+ }
1166
+ return await this.matchSequenceOptimized(patternElements, targetElements, patternIdx + 1, targetIdx + 1, filterEmpty);
1167
+ }
1253
1168
  }
1254
1169
  }
1255
1170
  exports.DebugPatternMatchingComparator = DebugPatternMatchingComparator;