Skip to content

Commit 76190f9

Browse files
committed
refactor(vnext): share embedded region lookup
1 parent ed079df commit 76190f9

4 files changed

Lines changed: 49 additions & 41 deletions

File tree

src/vnext/__tests__/source.test.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { describe, expect, it } from "vitest";
22
import {
33
createIdentitySqlSource,
44
createMaskedSqlSource,
5+
findSqlEmbeddedRegionAtOrAfter,
56
mapAnalysisRangeToOriginal,
67
mapOriginalRangeToAnalysis,
78
MAX_SQL_EMBEDDED_REGIONS,
@@ -188,6 +189,20 @@ describe("SQL source snapshots", () => {
188189
expect(source.analysisText).toBe(" b ");
189190
});
190191

192+
it("finds the first embedded region ending after a position", () => {
193+
const source = createMaskedSqlSource("abcdef", [
194+
{ from: 1, language: "python", to: 2 },
195+
{ from: 3, language: "jinja", to: 5 },
196+
]);
197+
198+
expect(findSqlEmbeddedRegionAtOrAfter(source, 0)).toBe(0);
199+
expect(findSqlEmbeddedRegionAtOrAfter(source, 1)).toBe(0);
200+
expect(findSqlEmbeddedRegionAtOrAfter(source, 2)).toBe(1);
201+
expect(findSqlEmbeddedRegionAtOrAfter(source, 4)).toBe(1);
202+
expect(findSqlEmbeddedRegionAtOrAfter(source, 5)).toBe(2);
203+
expect(findSqlEmbeddedRegionAtOrAfter(source, 6)).toBe(2);
204+
});
205+
191206
it.each([
192207
null,
193208
{},

src/vnext/bounded-sql-lexer.ts

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ import {
99
sqlIdentifierStartLengthAt,
1010
type SqlLexicalProfile,
1111
} from "./lexical.js";
12-
import type { SqlSourceSnapshot } from "./source.js";
12+
import {
13+
findSqlEmbeddedRegionAtOrAfter,
14+
type SqlSourceSnapshot,
15+
} from "./source.js";
1316

1417
export const MAX_BOUNDED_SQL_LEXEMES = 16_384;
1518

@@ -34,24 +37,6 @@ export type BoundedSqlLexerResource =
3437
| "dollar-quote-delimiter"
3538
| "lexical-token";
3639

37-
function findSqlRegionAtOrAfter(
38-
source: SqlSourceSnapshot,
39-
position: number,
40-
): number {
41-
let low = 0;
42-
let high = source.embeddedRegions.length;
43-
while (low < high) {
44-
const middle = low + Math.floor((high - low) / 2);
45-
const region = source.embeddedRegions[middle];
46-
if (!region || region.to <= position) {
47-
low = middle + 1;
48-
} else {
49-
high = middle;
50-
}
51-
}
52-
return low;
53-
}
54-
5540
export class BoundedSqlLexer {
5641
readonly #profile: SqlLexicalProfile;
5742
readonly #source: SqlSourceSnapshot;
@@ -72,7 +57,7 @@ export class BoundedSqlLexer {
7257
this.#cursor = from;
7358
this.#to = to;
7459
this.#profile = profile;
75-
this.#regionIndex = findSqlRegionAtOrAfter(source, from);
60+
this.#regionIndex = findSqlEmbeddedRegionAtOrAfter(source, from);
7661
}
7762

7863
next(): BoundedSqlLexeme | null {

src/vnext/query-site.ts

Lines changed: 11 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@ import {
55
type BoundedSqlLexerResource,
66
} from "./bounded-sql-lexer.js";
77
import type { SqlLexicalProfile } from "./lexical.js";
8-
import type { SqlSourceSnapshot } from "./source.js";
8+
import {
9+
findSqlEmbeddedRegionAtOrAfter,
10+
type SqlSourceSnapshot,
11+
} from "./source.js";
912
import type {
1013
ExactSqlStatementSlot,
1114
SqlStatementSlot,
@@ -200,30 +203,14 @@ function createRange(from: number, to: number): SqlQuerySiteRange {
200203
return Object.freeze(range);
201204
}
202205

203-
function findRegionAtOrAfter(
204-
source: SqlSourceSnapshot,
205-
position: number,
206-
): number {
207-
let low = 0;
208-
let high = source.embeddedRegions.length;
209-
while (low < high) {
210-
const middle = low + Math.floor((high - low) / 2);
211-
const region = source.embeddedRegions[middle];
212-
if (!region || region.to <= position) {
213-
low = middle + 1;
214-
} else {
215-
high = middle;
216-
}
217-
}
218-
return low;
219-
}
220-
221206
function regionContains(
222207
source: SqlSourceSnapshot,
223208
position: number,
224209
): boolean {
225210
const region =
226-
source.embeddedRegions[findRegionAtOrAfter(source, position)];
211+
source.embeddedRegions[
212+
findSqlEmbeddedRegionAtOrAfter(source, position)
213+
];
227214
return Boolean(
228215
region && region.from <= position && position < region.to,
229216
);
@@ -672,7 +659,10 @@ function intersectsRegion(
672659
from: number,
673660
to: number,
674661
): boolean {
675-
const region = source.embeddedRegions[findRegionAtOrAfter(source, from)];
662+
const region =
663+
source.embeddedRegions[
664+
findSqlEmbeddedRegionAtOrAfter(source, from)
665+
];
676666
return Boolean(region && region.from < to && from < region.to);
677667
}
678668

src/vnext/source.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,24 @@ export interface SqlSourceSnapshot {
3838
readonly originalText: string;
3939
}
4040

41+
export function findSqlEmbeddedRegionAtOrAfter(
42+
source: SqlSourceSnapshot,
43+
position: number,
44+
): number {
45+
let low = 0;
46+
let high = source.embeddedRegions.length;
47+
while (low < high) {
48+
const middle = low + Math.floor((high - low) / 2);
49+
const region = source.embeddedRegions[middle];
50+
if (!region || region.to <= position) {
51+
low = middle + 1;
52+
} else {
53+
high = middle;
54+
}
55+
}
56+
return low;
57+
}
58+
4159
interface MissingDataProperty {
4260
readonly found: false;
4361
}

0 commit comments

Comments
 (0)