Skip to content

Commit 7ab9d9c

Browse files
committed
Start with range start/end encoding/decoding
1 parent 6eb502f commit 7ab9d9c

File tree

4 files changed

+132
-6
lines changed

4 files changed

+132
-6
lines changed

src/builder/builder.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,15 +84,20 @@ export class ScopeInfoBuilder {
8484
}
8585

8686
startRange(line: number, column: number): this {
87-
this.#rangeStack.push({
87+
const range: GeneratedRange = {
8888
start: { line, column },
8989
end: { line, column },
9090
isStackFrame: false,
9191
isHidden: false,
9292
values: [],
9393
children: [],
94-
parent: this.#rangeStack.at(-1),
95-
});
94+
};
95+
96+
if (this.#rangeStack.length > 0) {
97+
range.parent = this.#rangeStack.at(-1);
98+
}
99+
100+
this.#rangeStack.push(range);
96101

97102
return this;
98103
}

src/codec.ts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ export const EmptyItem = Symbol("empty item");
3333
export type Item =
3434
| typeof EmptyItem
3535
| OriginalScopeStartItem
36-
| OriginalScopeEndItem;
37-
// | GeneratedStartItem
38-
// | GeneratedEndItem
36+
| OriginalScopeEndItem
37+
| GeneratedRangeStartItem
38+
| GeneratedRangeEndItem;
3939
// | VariablesItem
4040
// | BindingsItem;
4141

@@ -53,3 +53,16 @@ interface OriginalScopeEndItem {
5353
line: number;
5454
column: number;
5555
}
56+
57+
interface GeneratedRangeStartItem {
58+
tag: Tag.GENERATED_RANGE_START;
59+
flags: number;
60+
line?: number;
61+
column: number;
62+
}
63+
64+
interface GeneratedRangeEndItem {
65+
tag: Tag.GENERATED_RANGE_END;
66+
line?: number;
67+
column: number;
68+
}

src/decode/decode.ts

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import {
66
EmptyItem,
7+
GeneratedRangeFlags,
78
type Item,
89
OriginalScopeFlags,
910
type OriginalScopeStartItem,
@@ -112,6 +113,62 @@ class Decoder {
112113
}
113114
break;
114115
}
116+
case Tag.GENERATED_RANGE_START: {
117+
if (item.line !== undefined) {
118+
this.#rangeState.line += item.line;
119+
this.#rangeState.column = item.column;
120+
} else {
121+
this.#rangeState.column += item.column;
122+
}
123+
124+
const range: GeneratedRange = {
125+
start: {
126+
line: this.#rangeState.line,
127+
column: this.#rangeState.column,
128+
},
129+
end: {
130+
line: this.#rangeState.line,
131+
column: this.#rangeState.column,
132+
},
133+
isStackFrame: false,
134+
isHidden: false,
135+
values: [],
136+
children: [],
137+
};
138+
139+
this.#rangeStack.push(range);
140+
break;
141+
}
142+
case Tag.GENERATED_RANGE_END: {
143+
if (item.line !== undefined) {
144+
this.#rangeState.line += item.line;
145+
this.#rangeState.column = item.column;
146+
} else {
147+
this.#rangeState.column += item.column;
148+
}
149+
150+
const range = this.#rangeStack.pop();
151+
if (!range) {
152+
throw new Error(
153+
"Encountered GENERATED_RANGE_END wtihout matching GENERATED_RANGE_START!",
154+
);
155+
}
156+
157+
range.end = {
158+
line: this.#rangeState.line,
159+
column: this.#rangeState.column,
160+
};
161+
162+
if (this.#rangeStack.length > 0) {
163+
const parent = this.#rangeStack.at(-1)!;
164+
range.parent = parent;
165+
parent.children.push(range);
166+
} else {
167+
this.#ranges.push(range);
168+
Object.assign(this.#rangeState, DEFAULT_RANGE_STATE);
169+
}
170+
break;
171+
}
115172
}
116173
}
117174

@@ -161,6 +218,33 @@ class Decoder {
161218
};
162219
break;
163220
}
221+
case Tag.GENERATED_RANGE_START: {
222+
const flags = iter.nextUnsignedVLQ();
223+
const line = flags & GeneratedRangeFlags.HAS_LINE
224+
? iter.nextUnsignedVLQ()
225+
: undefined;
226+
227+
yield {
228+
tag,
229+
flags,
230+
line,
231+
column: iter.nextUnsignedVLQ(),
232+
};
233+
break;
234+
}
235+
case Tag.GENERATED_RANGE_END: {
236+
const lineOrColumn = iter.nextUnsignedVLQ();
237+
const maybeColumn = iter.hasNext() && iter.peek() !== ","
238+
? iter.nextUnsignedVLQ()
239+
: undefined;
240+
241+
if (maybeColumn !== undefined) {
242+
yield { tag, line: lineOrColumn, column: maybeColumn };
243+
} else {
244+
yield { tag, column: lineOrColumn };
245+
}
246+
break;
247+
}
164248
}
165249

166250
// Consume any trailing VLQ and the the ","

src/roundtrip.test.ts

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

7878
assertCodec(builder.build());
7979
});
80+
81+
it("handles a single top-level GeneratedRange on the same line", () => {
82+
builder.startRange(0, 5).endRange(0, 10);
83+
84+
assertCodec(builder.build());
85+
});
86+
87+
it("handles a single top-level GeneratedRange that spans multiple lines", () => {
88+
builder.startRange(0, 5).endRange(10, 2);
89+
90+
assertCodec(builder.build());
91+
});
92+
93+
it("handles multiple top-level GeneratedRagnes on the same line", () => {
94+
builder.startRange(0, 5).endRange(0, 10).startRange(0, 20).endRange(0, 30);
95+
96+
assertCodec(builder.build());
97+
});
98+
99+
it("handles multiple top-level GeneratedRanges that span multiple lines", () => {
100+
builder.startRange(0, 1).endRange(10, 2).startRange(20, 3).endRange(30, 4);
101+
102+
assertCodec(builder.build());
103+
});
80104
});

0 commit comments

Comments
 (0)