Skip to content

Commit 745d58b

Browse files
committed
JS: Polish templating implementation
Use visitor to attach capture marker.
1 parent cbb2abf commit 745d58b

3 files changed

Lines changed: 145 additions & 157 deletions

File tree

rewrite-javascript/rewrite/src/javascript/comparator.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1965,7 +1965,7 @@ export class JavaScriptSemanticComparatorVisitor extends JavaScriptComparatorVis
19651965
}
19661966

19671967
if (method.select && otherMethod.select) {
1968-
await this.visit(method.select.element, otherMethod.select.element);
1968+
await this.visitRightPadded(method.select, otherMethod.select as any);
19691969
}
19701970
}
19711971

@@ -1979,7 +1979,7 @@ export class JavaScriptSemanticComparatorVisitor extends JavaScriptComparatorVis
19791979
return this.abort(method);
19801980
}
19811981
for (let i = 0; i < method.typeParameters.elements.length; i++) {
1982-
await this.visit(method.typeParameters.elements[i].element, otherMethod.typeParameters.elements[i].element);
1982+
await this.visitRightPadded(method.typeParameters.elements[i], otherMethod.typeParameters.elements[i] as any);
19831983
if (!this.match) {
19841984
return this.abort(method);
19851985
}
@@ -1992,9 +1992,9 @@ export class JavaScriptSemanticComparatorVisitor extends JavaScriptComparatorVis
19921992
return this.abort(method);
19931993
}
19941994

1995-
// Compare arguments
1995+
// Compare arguments (visit RightPadded to check for markers)
19961996
for (let i = 0; i < method.arguments.elements.length; i++) {
1997-
await this.visit(method.arguments.elements[i].element, otherMethod.arguments.elements[i].element);
1997+
await this.visitRightPadded(method.arguments.elements[i], otherMethod.arguments.elements[i] as any);
19981998
if (!this.match) {
19991999
return this.abort(method);
20002000
}
@@ -2086,7 +2086,7 @@ export class JavaScriptSemanticComparatorVisitor extends JavaScriptComparatorVis
20862086

20872087
// Visit each variable in lock step
20882088
for (let i = 0; i < variableDeclarations.variables.length; i++) {
2089-
await this.visit(variableDeclarations.variables[i].element, otherVariableDeclarations.variables[i].element);
2089+
await this.visitRightPadded(variableDeclarations.variables[i], otherVariableDeclarations.variables[i] as any);
20902090
if (!this.match) return variableDeclarations;
20912091
}
20922092

@@ -2154,7 +2154,7 @@ export class JavaScriptSemanticComparatorVisitor extends JavaScriptComparatorVis
21542154

21552155
// Visit each parameter in lock step
21562156
for (let i = 0; i < methodDeclaration.parameters.elements.length; i++) {
2157-
await this.visit(methodDeclaration.parameters.elements[i].element, otherMethodDeclaration.parameters.elements[i].element);
2157+
await this.visitRightPadded(methodDeclaration.parameters.elements[i], otherMethodDeclaration.parameters.elements[i] as any);
21582158
if (!this.match) return methodDeclaration;
21592159
}
21602160

@@ -2170,7 +2170,7 @@ export class JavaScriptSemanticComparatorVisitor extends JavaScriptComparatorVis
21702170
}
21712171

21722172
for (let i = 0; i < methodDeclaration.throws.elements.length; i++) {
2173-
await this.visit(methodDeclaration.throws.elements[i].element, otherMethodDeclaration.throws.elements[i].element);
2173+
await this.visitRightPadded(methodDeclaration.throws.elements[i], otherMethodDeclaration.throws.elements[i] as any);
21742174
if (!this.match) return methodDeclaration;
21752175
}
21762176
}

rewrite-javascript/rewrite/src/javascript/templating/comparator.ts

Lines changed: 22 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16-
import {Cursor, isTree, Tree} from '../..';
16+
import {Cursor, Tree} from '../..';
1717
import {J} from '../../java';
1818
import {JS} from '../index';
1919
import {JavaScriptSemanticComparatorVisitor} from '../comparator';
20-
import {PlaceholderUtils, CaptureStorageValue} from './utils';
20+
import {CaptureMarker, CaptureStorageValue, PlaceholderUtils} from './utils';
2121

2222
/**
2323
* A comparator for pattern matching that is lenient about optional properties.
@@ -27,8 +27,8 @@ import {PlaceholderUtils, CaptureStorageValue} from './utils';
2727
export class PatternMatchingComparator extends JavaScriptSemanticComparatorVisitor {
2828
constructor(
2929
private readonly matcher: {
30-
handleCapture: (pattern: J, target: J, wrapper?: J.RightPadded<J>) => boolean;
31-
handleVariadicCapture: (pattern: J, targets: J[], wrappers?: J.RightPadded<J>[]) => boolean;
30+
handleCapture: (capture: CaptureMarker, target: J, wrapper?: J.RightPadded<J>) => boolean;
31+
handleVariadicCapture: (capture: CaptureMarker, targets: J[], wrappers?: J.RightPadded<J>[]) => boolean;
3232
saveState: () => Map<string, CaptureStorageValue>;
3333
restoreState: (state: Map<string, CaptureStorageValue>) => void;
3434
},
@@ -42,7 +42,7 @@ export class PatternMatchingComparator extends JavaScriptSemanticComparatorVisit
4242
// Check if the pattern node is a capture - this handles unwrapped captures
4343
// (Wrapped captures in J.RightPadded are handled by visitRightPadded override)
4444
if (PlaceholderUtils.isCapture(j as J)) {
45-
const success = this.matcher.handleCapture(j as J, p, undefined);
45+
const success = this.matcher.handleCapture(PlaceholderUtils.getCaptureMarker(j)!, p, undefined);
4646
if (!success) {
4747
return this.abort(j) as R;
4848
}
@@ -70,27 +70,17 @@ export class PatternMatchingComparator extends JavaScriptSemanticComparatorVisit
7070
return right;
7171
}
7272

73-
// Check if this RightPadded or its element has a CaptureMarker (attached during pattern construction)
74-
const element = right.element;
75-
let captureMarker = undefined;
76-
77-
// Check RightPadded itself
78-
if (right.markers) {
79-
captureMarker = PlaceholderUtils.getCaptureMarker(right);
80-
}
81-
82-
// Check element if it's a J node
83-
if (!captureMarker && isTree(element)) {
84-
captureMarker = PlaceholderUtils.getCaptureMarker(element);
85-
}
73+
// Check if this RightPadded has a CaptureMarker (attached during pattern construction)
74+
// Note: Markers are now only at the wrapper level, not at the element level
75+
const captureMarker = PlaceholderUtils.getCaptureMarker(right);
8676
if (captureMarker) {
8777
// Extract the target wrapper if it's also a RightPadded
8878
const isRightPadded = (p as any).kind === J.Kind.RightPadded;
8979
const targetWrapper = isRightPadded ? (p as unknown) as J.RightPadded<T> : undefined;
9080
const targetElement = isRightPadded ? targetWrapper!.element : p;
9181

9282
// Handle the capture with the wrapper - use the element for pattern matching
93-
const success = this.matcher.handleCapture(element as J, targetElement as J, targetWrapper as J.RightPadded<J> | undefined);
83+
const success = this.matcher.handleCapture(captureMarker, targetElement as J, targetWrapper as J.RightPadded<J> | undefined);
9484
if (!success) {
9585
return this.abort(right);
9686
}
@@ -141,9 +131,9 @@ export class PatternMatchingComparator extends JavaScriptSemanticComparatorVisit
141131
return this.abort(methodInvocation);
142132
}
143133

144-
// Visit each type parameter in lock step
134+
// Visit each type parameter in lock step (visit RightPadded to check for markers)
145135
for (let i = 0; i < methodInvocation.typeParameters.elements.length; i++) {
146-
await this.visit(methodInvocation.typeParameters.elements[i].element, otherMethodInvocation.typeParameters.elements[i].element);
136+
await this.visitRightPadded(methodInvocation.typeParameters.elements[i], otherMethodInvocation.typeParameters.elements[i] as any);
147137
if (!this.match) return methodInvocation;
148138
}
149139
}
@@ -163,7 +153,7 @@ export class PatternMatchingComparator extends JavaScriptSemanticComparatorVisit
163153
override async visitBlock(block: J.Block, other: J): Promise<J | undefined> {
164154
// Check if any statements have CaptureMarker indicating they're variadic
165155
const hasVariadicCapture = block.statements.some(stmt => {
166-
const captureMarker = PlaceholderUtils.getCaptureMarker(stmt.element);
156+
const captureMarker = PlaceholderUtils.getCaptureMarker(stmt);
167157
return captureMarker?.variadicOptions !== undefined;
168158
});
169159

@@ -261,8 +251,9 @@ export class PatternMatchingComparator extends JavaScriptSemanticComparatorVisit
261251
return targetIdx >= targetElements.length; // Success if all targets consumed
262252
}
263253

264-
const patternElement = patternElements[patternIdx].element;
265-
const captureMarker = PlaceholderUtils.getCaptureMarker(patternElement);
254+
// Check for markers at wrapper level only (markers are now only at the outermost level)
255+
const patternWrapper = patternElements[patternIdx];
256+
const captureMarker = PlaceholderUtils.getCaptureMarker(patternWrapper);
266257
const isVariadic = captureMarker?.variadicOptions !== undefined;
267258

268259
if (isVariadic) {
@@ -274,8 +265,7 @@ export class PatternMatchingComparator extends JavaScriptSemanticComparatorVisit
274265
// Calculate maximum possible consumption
275266
let nonVariadicRemainingPatterns = 0;
276267
for (let i = patternIdx + 1; i < patternElements.length; i++) {
277-
const nextPatternElement = patternElements[i].element;
278-
const nextCaptureMarker = PlaceholderUtils.getCaptureMarker(nextPatternElement);
268+
const nextCaptureMarker = PlaceholderUtils.getCaptureMarker(patternElements[i]);
279269
const nextIsVariadic = nextCaptureMarker?.variadicOptions !== undefined;
280270
if (!nextIsVariadic) {
281271
nonVariadicRemainingPatterns++;
@@ -290,24 +280,24 @@ export class PatternMatchingComparator extends JavaScriptSemanticComparatorVisit
290280
let pivotAt = -1;
291281

292282
if (patternIdx + 1 < patternElements.length && min <= maxPossible) {
293-
const nextPattern = patternElements[patternIdx + 1].element;
283+
const nextPattern = patternElements[patternIdx + 1];
294284

295285
// Scan through possible consumption amounts starting from min
296286
for (let tryConsume = min; tryConsume <= maxPossible; tryConsume++) {
297287
// Check if element after our consumption would match next pattern
298288
if (targetIdx + tryConsume < targetElements.length) {
299-
const candidateElement = targetElements[targetIdx + tryConsume].element;
289+
const candidateElement = targetElements[targetIdx + tryConsume];
300290

301291
// Skip J.Empty for arguments
302-
if (filterEmpty && candidateElement.kind === J.Kind.Empty) {
292+
if (filterEmpty && candidateElement.element.kind === J.Kind.Empty) {
303293
continue;
304294
}
305295

306296
// Test if next pattern matches this element
307297
const savedMatch = this.match;
308298
const savedState = this.matcher.saveState();
309299

310-
await this.visit(nextPattern, candidateElement);
300+
await this.visitRightPadded(nextPattern, candidateElement as any);
311301
const matchesNext = this.match;
312302

313303
this.match = savedMatch;
@@ -366,7 +356,7 @@ export class PatternMatchingComparator extends JavaScriptSemanticComparatorVisit
366356
const savedState = this.matcher.saveState();
367357

368358
// Handle the variadic capture
369-
const success = this.matcher.handleVariadicCapture(patternElement, capturedElements, capturedWrappers);
359+
const success = this.matcher.handleVariadicCapture(captureMarker, capturedElements, capturedWrappers);
370360
if (!success) {
371361
// Restore state and try next amount
372362
this.matcher.restoreState(savedState);
@@ -409,7 +399,7 @@ export class PatternMatchingComparator extends JavaScriptSemanticComparatorVisit
409399
const savedMatch = this.match;
410400
const savedState = this.matcher.saveState();
411401

412-
await this.visit(patternElement, targetElement);
402+
await this.visitRightPadded(patternWrapper, targetWrapper as any);
413403

414404
if (!this.match) {
415405
// Restore state on match failure

0 commit comments

Comments
 (0)