Skip to content

Commit

Permalink
Complete scopes and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
jridgewell committed Jun 25, 2024
1 parent 86b883c commit 29c3478
Show file tree
Hide file tree
Showing 3 changed files with 478 additions and 65 deletions.
323 changes: 258 additions & 65 deletions src/scopes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import {
write,
td,
resetPos,
decodeFirstOctet,
semicolon,
} from './vlq';

type Line = number;
Expand All @@ -26,6 +28,7 @@ export type OriginalScope =
2: Line;
3: Column;
4: Kind;
vars?: Var[];
length: 5;
}
| {
Expand All @@ -35,34 +38,15 @@ export type OriginalScope =
3: Column;
4: Kind;
5: Name;
length: 6;
}
| {
0: Line;
1: Column;
2: Line;
3: Column;
4: Kind;
vars: Var[];
length: 5;
}
| {
0: Line;
1: Column;
2: Line;
3: Column;
4: Kind;
5: Name;
vars: Var[];
vars?: Var[];
length: 6;
};

const NO_NAME = -1;
// const NO_SCOPE = -1;
const NO_SOURCE = -1;

export function decodeOriginalScopes(input: string): OriginalScope[] {
let line = 0;
let namesIndex = 0;
const scopes: OriginalScope[] = [];
const stack: OriginalScope[] = [];

Expand All @@ -79,7 +63,7 @@ export function decodeOriginalScopes(input: string): OriginalScope[] {

const kind = decodeInteger(input, posOut, 0);
const fields = decodeInteger(input, posOut, 0);
const name = fields & 0b1 ? decodeInteger(input, posOut, namesIndex) : NO_NAME;
const name = fields & 0b0001 ? decodeInteger(input, posOut, 0) : NO_NAME;
const scope: OriginalScope =
name === NO_NAME ? [line, column, 0, 0, kind] : [line, column, 0, 0, kind, name];
scopes.push(scope);
Expand All @@ -88,7 +72,7 @@ export function decodeOriginalScopes(input: string): OriginalScope[] {
const index = indexOf(input, ',', posOut);
if (posOut < index) {
const vars: Var[] = [];
(scope as any).vars = vars;
scope.vars = vars;
while (posOut < index) {
const varsIndex = decodeInteger(input, posOut, 0);
vars.push(varsIndex);
Expand All @@ -113,7 +97,6 @@ export function encodeOriginalScopes(scopes: OriginalScope[]): string {
let lastEndLine = scopes[0][2] + 1;
let lastEndColumn = scopes[0][3];
let line = 0;
let namesIndex = 0;

for (let i = 0; i < scopes.length; i++) {
const scope = scopes[i];
Expand Down Expand Up @@ -143,8 +126,10 @@ export function encodeOriginalScopes(scopes: OriginalScope[]): string {
lastEndColumn = endColumn;

encodeInteger(buf, posOut, kind, 0);
encodeInteger(buf, posOut, name === NO_NAME ? 0 : 1, 0);
if (name !== NO_NAME) namesIndex = encodeInteger(buf, posOut, name, namesIndex);

const fields = name === NO_NAME ? 0 : 1;
encodeInteger(buf, posOut, fields, 0);
if (name !== NO_NAME) encodeInteger(buf, posOut, name, 0);

for (const v of vars) {
out = maybeFlush(out, sub, posOut, buf, subLength);
Expand All @@ -165,50 +150,258 @@ export function encodeOriginalScopes(scopes: OriginalScope[]): string {
return out + td.decode(buf.subarray(0, posOut));
}

export type GeneratedRange =
| {
0: Line;
1: Column;
2: Line;
3: Column;
4: SourcesIndex;
5: ScopesIndex;
}
| {
0: Line;
1: Column;
2: Line;
3: Column;
4: SourcesIndex;
5: ScopesIndex;
callsite: CallSite;
}
| {
0: Line;
1: Column;
2: Line;
3: Column;
4: SourcesIndex;
5: ScopesIndex;
bindings: ExpressionBinding[];
}
| {
0: Line;
1: Column;
2: Line;
3: Column;
4: SourcesIndex;
5: ScopesIndex;
callsite: CallSite;
bindings: ExpressionBinding[];
};
// type OptionalFields<T> = {
// [K in keyof T]: K extends number ? T[K] : never;
// } & {
// [K in keyof T]: K extends string ? T[K] : never;
// };
export type GeneratedRange = {
0: Line;
1: Column;
2: Line;
3: Column;
4: SourcesIndex;
5: ScopesIndex;
callsite?: CallSite;
bindings?: ExpressionBinding[][];
isScope?: boolean;
};
export type CallSite = [SourcesIndex, Line, Column];
export type ExpressionBinding = [Name] | [Name, Line, Column];

export function decodeGeneratedRanges(input: string): GeneratedRange[] {
return [];
let genLine = 0;
let genColumn = 0;
let definitionSourcesIndex = 0;
let definitionScopeIndex = 0;
let callsiteSourcesIndex = 0;
let callsiteLine = 0;
let callsiteColumn = 0;
let bindingLine = 0;
let bindingColumn = 0;

const ranges: GeneratedRange[] = [];
const stack: GeneratedRange[] = [];
let index = 0;
do {
const semi = indexOf(input, ';', index);
genColumn = 0;

for (let i = index; i < semi; i = posOut + 1) {
genColumn = decodeInteger(input, i, genColumn);
if (hasMoreVlq(input, posOut, semi)) {
const fields = decodeInteger(input, posOut, 0);
let defSourcesIndex = NO_SOURCE;
let defScopeIndex = NO_SOURCE;

if (fields & 0b0001) {
defSourcesIndex = decodeInteger(input, posOut, definitionSourcesIndex);
if (definitionSourcesIndex !== defSourcesIndex) {
definitionScopeIndex = 0;
definitionSourcesIndex = defSourcesIndex;
}
defScopeIndex = definitionScopeIndex = decodeInteger(input, posOut, definitionScopeIndex);
}

const range: GeneratedRange = [genLine, genColumn, 0, 0, defSourcesIndex, defScopeIndex];

if (fields & 0b0010) {
const callSourcesIndex = decodeInteger(input, posOut, callsiteSourcesIndex);
const sameSource = callSourcesIndex === callsiteSourcesIndex;
const callLine = decodeInteger(input, posOut, sameSource ? callsiteLine : 0);
const sameLine = sameSource && callLine === callsiteLine;
callsiteColumn = decodeInteger(input, posOut, sameLine ? callsiteColumn : 0);

callsiteSourcesIndex = callSourcesIndex;
callsiteLine = callLine;
range.callsite = [callsiteSourcesIndex, callsiteLine, callsiteColumn];
}
if (fields & 0b0100) {
range.isScope = true;
}

if (hasMoreVlq(input, posOut, semi)) {
debugger;
const bindings: ExpressionBinding[][] = [];
range.bindings = bindings;
do {
bindingLine = genLine;
bindingColumn = genColumn;
let name = decodeInteger(input, posOut, 0);
const hasExpressions = decodeFirstOctet(input, posOut);
const binding: ExpressionBinding[] = [[name]];
bindings.push(binding);
if (hasExpressions < -1) {
const expressionsCount = decodeInteger(input, posOut, 0);
for (let i = -1; i > expressionsCount; i--) {
const prevBindingLine = bindingLine;
bindingLine = decodeInteger(input, posOut, bindingLine);
bindingColumn = decodeInteger(
input,
posOut,
bindingLine === prevBindingLine ? bindingColumn : 0,
);
name = decodeInteger(input, posOut, 0);
}
binding.push([name, bindingLine, bindingColumn] as ExpressionBinding);
}
} while (hasMoreVlq(input, posOut, semi));
}

ranges.push(range);
stack.push(range);
} else {
const range = stack.pop()!;
range[2] = genLine;
range[3] = genColumn;
}
}

genLine++;
index = semi + 1;
} while (index <= input.length);

return ranges;
}

export function encodeGeneratedRanges(ranges: GeneratedRange[]): string {
return '';
let out = '';
if (ranges.length === 0) return out;

const bufLength = 1024 * 16;
const subLength = bufLength - (7 * 7 + 1);
const buf = new Uint8Array(bufLength);
const sub = buf.subarray(0, subLength);
resetPos();

const endStack: number[] = [];
let lastEndLine = ranges[0][2] + 1;
let lastEndColumn = ranges[0][3];
let line = 0;
let genColumn = 0;
let definitionSourcesIndex = 0;
let definitionScopeIndex = 0;
let callsiteSourcesIndex = 0;
let callsiteLine = 0;
let callsiteColumn = 0;
for (let i = 0; i < ranges.length; i++) {
const range = ranges[i];
const {
0: startLine,
1: startColumn,
2: endLine,
3: endColumn,
4: defSourcesIndex,
5: defScopeIndex,
} = range;
const isScope = 'isScope' in range && range.isScope;
const hasCallsite = 'callsite' in range;
const hasBindings = 'bindings' in range;

while (startLine > lastEndLine || (startLine === lastEndLine && startColumn >= lastEndColumn)) {
if (line < lastEndLine) {
out = catchupLine(out, buf, bufLength, line, lastEndLine);
line = lastEndLine;
genColumn = 0;
} else {
out = maybeFlush(out, buf, posOut, buf, bufLength);
write(buf, posOut, comma);
}
out = maybeFlush(out, sub, posOut, buf, subLength);
genColumn = encodeInteger(buf, posOut, lastEndColumn, genColumn);

lastEndColumn = endStack.pop()!;
lastEndLine = endStack.pop()!;
}
if (line < startLine) {
out = catchupLine(out, buf, bufLength, line, startLine);
line = startLine;
genColumn = 0;
} else if (i > 0) {
out = maybeFlush(out, buf, posOut, buf, bufLength);
write(buf, posOut, comma);
}

out = maybeFlush(out, sub, posOut, buf, subLength);
genColumn = encodeInteger(buf, posOut, range[1], genColumn);
endStack.push(lastEndLine);
endStack.push(lastEndColumn);
lastEndLine = endLine;
lastEndColumn = endColumn;

const fields =
(defSourcesIndex === NO_SOURCE ? 0 : 0b0001) |
(hasCallsite ? 0b0010 : 0) |
(isScope ? 0b0100 : 0);
encodeInteger(buf, posOut, fields, 0);

if (defSourcesIndex !== NO_SOURCE) {
if (defSourcesIndex !== definitionSourcesIndex) definitionScopeIndex = 0;
definitionSourcesIndex = encodeInteger(buf, posOut, defSourcesIndex, definitionSourcesIndex);
definitionScopeIndex = encodeInteger(buf, posOut, defScopeIndex, definitionScopeIndex);
}

if (hasCallsite) {
const { 0: callSourcesIndex, 1: callLine, 2: callColumn } = range.callsite!;
if (callSourcesIndex !== callsiteSourcesIndex) {
callsiteLine = 0;
callsiteColumn = 0;
} else if (callLine !== callsiteLine) {
callsiteColumn = 0;
}
callsiteSourcesIndex = encodeInteger(buf, posOut, callSourcesIndex, callsiteSourcesIndex);
callsiteLine = encodeInteger(buf, posOut, callLine, callsiteLine);
callsiteColumn = encodeInteger(buf, posOut, callColumn, callsiteColumn);
}

if (hasBindings) {
for (const binding of range.bindings!) {
out = maybeFlush(out, sub, posOut, buf, subLength);
encodeInteger(buf, posOut, binding[0][0], 0);
if (binding.length > 1) {
encodeInteger(buf, posOut, -binding.length, 0);
let bindingStartLine = startLine;
let bindingStartColumn = startColumn;
for (let i = 1; i < binding.length; i++) {
out = maybeFlush(out, sub, posOut, buf, subLength);
const expression = binding[i];
bindingStartLine = encodeInteger(buf, posOut, expression[1]!, bindingStartLine);
bindingStartColumn = encodeInteger(buf, posOut, expression[2]!, bindingStartColumn);
encodeInteger(buf, posOut, expression[0]!, 0);
}
}
}
}
}
while (endStack.length > 0) {
if (line < lastEndLine) {
out = catchupLine(out, buf, bufLength, line, lastEndLine);
line = lastEndLine;
genColumn = 0;
} else {
out = maybeFlush(out, buf, posOut, buf, bufLength);
write(buf, posOut, comma);
}
out = maybeFlush(out, sub, posOut, buf, subLength);
genColumn = encodeInteger(buf, posOut, lastEndColumn, genColumn);

lastEndColumn = endStack.pop()!;
lastEndLine = endStack.pop()!;
}

return out + td.decode(buf.subarray(0, posOut));
}

function catchupLine(
build: string,
buf: Uint8Array,
bufLength: number,
lastLine: number,
line: number,
) {
do {
build = maybeFlush(build, buf, posOut, buf, bufLength);
write(buf, posOut, semicolon);
} while (++lastLine < line);
return build;
}
Loading

0 comments on commit 29c3478

Please sign in to comment.