Skip to content

Commit 888bc72

Browse files
committed
fix: Associate sub-range bindings with the correct range
Fixes #1
1 parent b2e82d4 commit 888bc72

File tree

2 files changed

+42
-5
lines changed

2 files changed

+42
-5
lines changed

src/decode/decode.ts

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,10 @@ class Decoder {
127127
readonly #rangeStack: GeneratedRange[] = [];
128128

129129
#flatOriginalScopes: OriginalScope[] = [];
130-
#subRangeBindingsForRange = new Map<number, [number, number, number][]>();
130+
#subRangeBindingsForRange = new Map<
131+
GeneratedRange,
132+
Map<number, [number, number, number][]>
133+
>();
131134

132135
constructor(scopes: string, names: string[], options: DecodeOptions) {
133136
this.#encodedScopes = scopes;
@@ -403,7 +406,6 @@ class Decoder {
403406
}
404407

405408
this.#rangeStack.push(range);
406-
this.#subRangeBindingsForRange.clear();
407409
}
408410

409411
#handleGeneratedRangeBindingsItem(valueIdxs: number[]) {
@@ -428,13 +430,25 @@ class Decoder {
428430
variableIndex: number,
429431
bindings: [number, number, number][],
430432
) {
431-
if (this.#subRangeBindingsForRange.has(variableIndex)) {
433+
const range = this.#rangeStack.at(-1);
434+
if (!range) {
435+
this.#throwInStrictMode(
436+
"Encountered GENERATED_RANGE_SUBRANGE_BINDING without surrounding GENERATED_RANGE_START",
437+
);
438+
return;
439+
}
440+
let subRangeBindings = this.#subRangeBindingsForRange.get(range);
441+
if (!subRangeBindings) {
442+
subRangeBindings = new Map();
443+
this.#subRangeBindingsForRange.set(range, subRangeBindings);
444+
}
445+
if (subRangeBindings.has(variableIndex)) {
432446
this.#throwInStrictMode(
433447
"Encountered multiple GENERATED_RANGE_SUBRANGE_BINDING items for the same variable",
434448
);
435449
return;
436450
}
437-
this.#subRangeBindingsForRange.set(variableIndex, bindings);
451+
subRangeBindings.set(variableIndex, bindings);
438452
}
439453

440454
#handleGeneratedRangeCallSite(
@@ -490,7 +504,10 @@ class Decoder {
490504
}
491505

492506
#handleGeneratedRangeSubRangeBindings(range: GeneratedRange) {
493-
for (const [variableIndex, bindings] of this.#subRangeBindingsForRange) {
507+
const subRangeBindings = this.#subRangeBindingsForRange.get(range);
508+
if (!subRangeBindings) return;
509+
510+
for (const [variableIndex, bindings] of subRangeBindings) {
494511
const value = range.values[variableIndex];
495512
const subRanges: SubRangeBinding[] = [];
496513
range.values[variableIndex] = subRanges;

src/roundtrip.test.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,4 +269,24 @@ describe("round trip", () => {
269269

270270
assertCodec(builder.build());
271271
});
272+
273+
// Regression test for issue #1.
274+
it("handles sub-ranges correctly when the range has children", () => {
275+
builder.startScope(0, 0, { variables: ["x"], key: "root" }).endScope(1, 19)
276+
.startRange(0, 0, {
277+
scopeKey: "root",
278+
values: [[{
279+
from: { line: 0, column: 0 },
280+
to: { line: 1, column: 0 },
281+
value: '"foo"',
282+
}, {
283+
from: { line: 1, column: 0 },
284+
to: { line: 1, column: 19 },
285+
value: '"bar"',
286+
}]],
287+
}).startRange(0, 5)
288+
.endRange(0, 10).endRange(1, 19);
289+
290+
assertCodec(builder.build());
291+
});
272292
});

0 commit comments

Comments
 (0)