| 1 | import { StringReader, StringWriter } from './strings';
|
|---|
| 2 | import { comma, decodeInteger, encodeInteger, hasMoreVlq, semicolon } from './vlq';
|
|---|
| 3 |
|
|---|
| 4 | const EMPTY: any[] = [];
|
|---|
| 5 |
|
|---|
| 6 | type Line = number;
|
|---|
| 7 | type Column = number;
|
|---|
| 8 | type Kind = number;
|
|---|
| 9 | type Name = number;
|
|---|
| 10 | type Var = number;
|
|---|
| 11 | type SourcesIndex = number;
|
|---|
| 12 | type ScopesIndex = number;
|
|---|
| 13 |
|
|---|
| 14 | type Mix<A, B, O> = (A & O) | (B & O);
|
|---|
| 15 |
|
|---|
| 16 | export type OriginalScope = Mix<
|
|---|
| 17 | [Line, Column, Line, Column, Kind],
|
|---|
| 18 | [Line, Column, Line, Column, Kind, Name],
|
|---|
| 19 | { vars: Var[] }
|
|---|
| 20 | >;
|
|---|
| 21 |
|
|---|
| 22 | export type GeneratedRange = Mix<
|
|---|
| 23 | [Line, Column, Line, Column],
|
|---|
| 24 | [Line, Column, Line, Column, SourcesIndex, ScopesIndex],
|
|---|
| 25 | {
|
|---|
| 26 | callsite: CallSite | null;
|
|---|
| 27 | bindings: Binding[];
|
|---|
| 28 | isScope: boolean;
|
|---|
| 29 | }
|
|---|
| 30 | >;
|
|---|
| 31 | export type CallSite = [SourcesIndex, Line, Column];
|
|---|
| 32 | type Binding = BindingExpressionRange[];
|
|---|
| 33 | export type BindingExpressionRange = [Name] | [Name, Line, Column];
|
|---|
| 34 |
|
|---|
| 35 | export function decodeOriginalScopes(input: string): OriginalScope[] {
|
|---|
| 36 | const { length } = input;
|
|---|
| 37 | const reader = new StringReader(input);
|
|---|
| 38 | const scopes: OriginalScope[] = [];
|
|---|
| 39 | const stack: OriginalScope[] = [];
|
|---|
| 40 | let line = 0;
|
|---|
| 41 |
|
|---|
| 42 | for (; reader.pos < length; reader.pos++) {
|
|---|
| 43 | line = decodeInteger(reader, line);
|
|---|
| 44 | const column = decodeInteger(reader, 0);
|
|---|
| 45 |
|
|---|
| 46 | if (!hasMoreVlq(reader, length)) {
|
|---|
| 47 | const last = stack.pop()!;
|
|---|
| 48 | last[2] = line;
|
|---|
| 49 | last[3] = column;
|
|---|
| 50 | continue;
|
|---|
| 51 | }
|
|---|
| 52 |
|
|---|
| 53 | const kind = decodeInteger(reader, 0);
|
|---|
| 54 | const fields = decodeInteger(reader, 0);
|
|---|
| 55 | const hasName = fields & 0b0001;
|
|---|
| 56 |
|
|---|
| 57 | const scope: OriginalScope = (
|
|---|
| 58 | hasName ? [line, column, 0, 0, kind, decodeInteger(reader, 0)] : [line, column, 0, 0, kind]
|
|---|
| 59 | ) as OriginalScope;
|
|---|
| 60 |
|
|---|
| 61 | let vars: Var[] = EMPTY;
|
|---|
| 62 | if (hasMoreVlq(reader, length)) {
|
|---|
| 63 | vars = [];
|
|---|
| 64 | do {
|
|---|
| 65 | const varsIndex = decodeInteger(reader, 0);
|
|---|
| 66 | vars.push(varsIndex);
|
|---|
| 67 | } while (hasMoreVlq(reader, length));
|
|---|
| 68 | }
|
|---|
| 69 | scope.vars = vars;
|
|---|
| 70 |
|
|---|
| 71 | scopes.push(scope);
|
|---|
| 72 | stack.push(scope);
|
|---|
| 73 | }
|
|---|
| 74 |
|
|---|
| 75 | return scopes;
|
|---|
| 76 | }
|
|---|
| 77 |
|
|---|
| 78 | export function encodeOriginalScopes(scopes: OriginalScope[]): string {
|
|---|
| 79 | const writer = new StringWriter();
|
|---|
| 80 |
|
|---|
| 81 | for (let i = 0; i < scopes.length; ) {
|
|---|
| 82 | i = _encodeOriginalScopes(scopes, i, writer, [0]);
|
|---|
| 83 | }
|
|---|
| 84 |
|
|---|
| 85 | return writer.flush();
|
|---|
| 86 | }
|
|---|
| 87 |
|
|---|
| 88 | function _encodeOriginalScopes(
|
|---|
| 89 | scopes: OriginalScope[],
|
|---|
| 90 | index: number,
|
|---|
| 91 | writer: StringWriter,
|
|---|
| 92 | state: [
|
|---|
| 93 | number, // GenColumn
|
|---|
| 94 | ],
|
|---|
| 95 | ): number {
|
|---|
| 96 | const scope = scopes[index];
|
|---|
| 97 | const { 0: startLine, 1: startColumn, 2: endLine, 3: endColumn, 4: kind, vars } = scope;
|
|---|
| 98 |
|
|---|
| 99 | if (index > 0) writer.write(comma);
|
|---|
| 100 |
|
|---|
| 101 | state[0] = encodeInteger(writer, startLine, state[0]);
|
|---|
| 102 | encodeInteger(writer, startColumn, 0);
|
|---|
| 103 | encodeInteger(writer, kind, 0);
|
|---|
| 104 |
|
|---|
| 105 | const fields = scope.length === 6 ? 0b0001 : 0;
|
|---|
| 106 | encodeInteger(writer, fields, 0);
|
|---|
| 107 | if (scope.length === 6) encodeInteger(writer, scope[5], 0);
|
|---|
| 108 |
|
|---|
| 109 | for (const v of vars) {
|
|---|
| 110 | encodeInteger(writer, v, 0);
|
|---|
| 111 | }
|
|---|
| 112 |
|
|---|
| 113 | for (index++; index < scopes.length; ) {
|
|---|
| 114 | const next = scopes[index];
|
|---|
| 115 | const { 0: l, 1: c } = next;
|
|---|
| 116 | if (l > endLine || (l === endLine && c >= endColumn)) {
|
|---|
| 117 | break;
|
|---|
| 118 | }
|
|---|
| 119 | index = _encodeOriginalScopes(scopes, index, writer, state);
|
|---|
| 120 | }
|
|---|
| 121 |
|
|---|
| 122 | writer.write(comma);
|
|---|
| 123 | state[0] = encodeInteger(writer, endLine, state[0]);
|
|---|
| 124 | encodeInteger(writer, endColumn, 0);
|
|---|
| 125 |
|
|---|
| 126 | return index;
|
|---|
| 127 | }
|
|---|
| 128 |
|
|---|
| 129 | export function decodeGeneratedRanges(input: string): GeneratedRange[] {
|
|---|
| 130 | const { length } = input;
|
|---|
| 131 | const reader = new StringReader(input);
|
|---|
| 132 | const ranges: GeneratedRange[] = [];
|
|---|
| 133 | const stack: GeneratedRange[] = [];
|
|---|
| 134 |
|
|---|
| 135 | let genLine = 0;
|
|---|
| 136 | let definitionSourcesIndex = 0;
|
|---|
| 137 | let definitionScopeIndex = 0;
|
|---|
| 138 | let callsiteSourcesIndex = 0;
|
|---|
| 139 | let callsiteLine = 0;
|
|---|
| 140 | let callsiteColumn = 0;
|
|---|
| 141 | let bindingLine = 0;
|
|---|
| 142 | let bindingColumn = 0;
|
|---|
| 143 |
|
|---|
| 144 | do {
|
|---|
| 145 | const semi = reader.indexOf(';');
|
|---|
| 146 | let genColumn = 0;
|
|---|
| 147 |
|
|---|
| 148 | for (; reader.pos < semi; reader.pos++) {
|
|---|
| 149 | genColumn = decodeInteger(reader, genColumn);
|
|---|
| 150 |
|
|---|
| 151 | if (!hasMoreVlq(reader, semi)) {
|
|---|
| 152 | const last = stack.pop()!;
|
|---|
| 153 | last[2] = genLine;
|
|---|
| 154 | last[3] = genColumn;
|
|---|
| 155 | continue;
|
|---|
| 156 | }
|
|---|
| 157 |
|
|---|
| 158 | const fields = decodeInteger(reader, 0);
|
|---|
| 159 | const hasDefinition = fields & 0b0001;
|
|---|
| 160 | const hasCallsite = fields & 0b0010;
|
|---|
| 161 | const hasScope = fields & 0b0100;
|
|---|
| 162 |
|
|---|
| 163 | let callsite: CallSite | null = null;
|
|---|
| 164 | let bindings: Binding[] = EMPTY;
|
|---|
| 165 | let range: GeneratedRange;
|
|---|
| 166 | if (hasDefinition) {
|
|---|
| 167 | const defSourcesIndex = decodeInteger(reader, definitionSourcesIndex);
|
|---|
| 168 | definitionScopeIndex = decodeInteger(
|
|---|
| 169 | reader,
|
|---|
| 170 | definitionSourcesIndex === defSourcesIndex ? definitionScopeIndex : 0,
|
|---|
| 171 | );
|
|---|
| 172 |
|
|---|
| 173 | definitionSourcesIndex = defSourcesIndex;
|
|---|
| 174 | range = [genLine, genColumn, 0, 0, defSourcesIndex, definitionScopeIndex] as GeneratedRange;
|
|---|
| 175 | } else {
|
|---|
| 176 | range = [genLine, genColumn, 0, 0] as GeneratedRange;
|
|---|
| 177 | }
|
|---|
| 178 |
|
|---|
| 179 | range.isScope = !!hasScope;
|
|---|
| 180 |
|
|---|
| 181 | if (hasCallsite) {
|
|---|
| 182 | const prevCsi = callsiteSourcesIndex;
|
|---|
| 183 | const prevLine = callsiteLine;
|
|---|
| 184 | callsiteSourcesIndex = decodeInteger(reader, callsiteSourcesIndex);
|
|---|
| 185 | const sameSource = prevCsi === callsiteSourcesIndex;
|
|---|
| 186 | callsiteLine = decodeInteger(reader, sameSource ? callsiteLine : 0);
|
|---|
| 187 | callsiteColumn = decodeInteger(
|
|---|
| 188 | reader,
|
|---|
| 189 | sameSource && prevLine === callsiteLine ? callsiteColumn : 0,
|
|---|
| 190 | );
|
|---|
| 191 |
|
|---|
| 192 | callsite = [callsiteSourcesIndex, callsiteLine, callsiteColumn];
|
|---|
| 193 | }
|
|---|
| 194 | range.callsite = callsite;
|
|---|
| 195 |
|
|---|
| 196 | if (hasMoreVlq(reader, semi)) {
|
|---|
| 197 | bindings = [];
|
|---|
| 198 | do {
|
|---|
| 199 | bindingLine = genLine;
|
|---|
| 200 | bindingColumn = genColumn;
|
|---|
| 201 | const expressionsCount = decodeInteger(reader, 0);
|
|---|
| 202 | let expressionRanges: BindingExpressionRange[];
|
|---|
| 203 | if (expressionsCount < -1) {
|
|---|
| 204 | expressionRanges = [[decodeInteger(reader, 0)]];
|
|---|
| 205 | for (let i = -1; i > expressionsCount; i--) {
|
|---|
| 206 | const prevBl = bindingLine;
|
|---|
| 207 | bindingLine = decodeInteger(reader, bindingLine);
|
|---|
| 208 | bindingColumn = decodeInteger(reader, bindingLine === prevBl ? bindingColumn : 0);
|
|---|
| 209 | const expression = decodeInteger(reader, 0);
|
|---|
| 210 | expressionRanges.push([expression, bindingLine, bindingColumn]);
|
|---|
| 211 | }
|
|---|
| 212 | } else {
|
|---|
| 213 | expressionRanges = [[expressionsCount]];
|
|---|
| 214 | }
|
|---|
| 215 | bindings.push(expressionRanges);
|
|---|
| 216 | } while (hasMoreVlq(reader, semi));
|
|---|
| 217 | }
|
|---|
| 218 | range.bindings = bindings;
|
|---|
| 219 |
|
|---|
| 220 | ranges.push(range);
|
|---|
| 221 | stack.push(range);
|
|---|
| 222 | }
|
|---|
| 223 |
|
|---|
| 224 | genLine++;
|
|---|
| 225 | reader.pos = semi + 1;
|
|---|
| 226 | } while (reader.pos < length);
|
|---|
| 227 |
|
|---|
| 228 | return ranges;
|
|---|
| 229 | }
|
|---|
| 230 |
|
|---|
| 231 | export function encodeGeneratedRanges(ranges: GeneratedRange[]): string {
|
|---|
| 232 | if (ranges.length === 0) return '';
|
|---|
| 233 |
|
|---|
| 234 | const writer = new StringWriter();
|
|---|
| 235 |
|
|---|
| 236 | for (let i = 0; i < ranges.length; ) {
|
|---|
| 237 | i = _encodeGeneratedRanges(ranges, i, writer, [0, 0, 0, 0, 0, 0, 0]);
|
|---|
| 238 | }
|
|---|
| 239 |
|
|---|
| 240 | return writer.flush();
|
|---|
| 241 | }
|
|---|
| 242 |
|
|---|
| 243 | function _encodeGeneratedRanges(
|
|---|
| 244 | ranges: GeneratedRange[],
|
|---|
| 245 | index: number,
|
|---|
| 246 | writer: StringWriter,
|
|---|
| 247 | state: [
|
|---|
| 248 | number, // GenLine
|
|---|
| 249 | number, // GenColumn
|
|---|
| 250 | number, // DefSourcesIndex
|
|---|
| 251 | number, // DefScopesIndex
|
|---|
| 252 | number, // CallSourcesIndex
|
|---|
| 253 | number, // CallLine
|
|---|
| 254 | number, // CallColumn
|
|---|
| 255 | ],
|
|---|
| 256 | ): number {
|
|---|
| 257 | const range = ranges[index];
|
|---|
| 258 | const {
|
|---|
| 259 | 0: startLine,
|
|---|
| 260 | 1: startColumn,
|
|---|
| 261 | 2: endLine,
|
|---|
| 262 | 3: endColumn,
|
|---|
| 263 | isScope,
|
|---|
| 264 | callsite,
|
|---|
| 265 | bindings,
|
|---|
| 266 | } = range;
|
|---|
| 267 |
|
|---|
| 268 | if (state[0] < startLine) {
|
|---|
| 269 | catchupLine(writer, state[0], startLine);
|
|---|
| 270 | state[0] = startLine;
|
|---|
| 271 | state[1] = 0;
|
|---|
| 272 | } else if (index > 0) {
|
|---|
| 273 | writer.write(comma);
|
|---|
| 274 | }
|
|---|
| 275 |
|
|---|
| 276 | state[1] = encodeInteger(writer, range[1], state[1]);
|
|---|
| 277 |
|
|---|
| 278 | const fields =
|
|---|
| 279 | (range.length === 6 ? 0b0001 : 0) | (callsite ? 0b0010 : 0) | (isScope ? 0b0100 : 0);
|
|---|
| 280 | encodeInteger(writer, fields, 0);
|
|---|
| 281 |
|
|---|
| 282 | if (range.length === 6) {
|
|---|
| 283 | const { 4: sourcesIndex, 5: scopesIndex } = range;
|
|---|
| 284 | if (sourcesIndex !== state[2]) {
|
|---|
| 285 | state[3] = 0;
|
|---|
| 286 | }
|
|---|
| 287 | state[2] = encodeInteger(writer, sourcesIndex, state[2]);
|
|---|
| 288 | state[3] = encodeInteger(writer, scopesIndex, state[3]);
|
|---|
| 289 | }
|
|---|
| 290 |
|
|---|
| 291 | if (callsite) {
|
|---|
| 292 | const { 0: sourcesIndex, 1: callLine, 2: callColumn } = range.callsite!;
|
|---|
| 293 | if (sourcesIndex !== state[4]) {
|
|---|
| 294 | state[5] = 0;
|
|---|
| 295 | state[6] = 0;
|
|---|
| 296 | } else if (callLine !== state[5]) {
|
|---|
| 297 | state[6] = 0;
|
|---|
| 298 | }
|
|---|
| 299 | state[4] = encodeInteger(writer, sourcesIndex, state[4]);
|
|---|
| 300 | state[5] = encodeInteger(writer, callLine, state[5]);
|
|---|
| 301 | state[6] = encodeInteger(writer, callColumn, state[6]);
|
|---|
| 302 | }
|
|---|
| 303 |
|
|---|
| 304 | if (bindings) {
|
|---|
| 305 | for (const binding of bindings) {
|
|---|
| 306 | if (binding.length > 1) encodeInteger(writer, -binding.length, 0);
|
|---|
| 307 | const expression = binding[0][0];
|
|---|
| 308 | encodeInteger(writer, expression, 0);
|
|---|
| 309 | let bindingStartLine = startLine;
|
|---|
| 310 | let bindingStartColumn = startColumn;
|
|---|
| 311 | for (let i = 1; i < binding.length; i++) {
|
|---|
| 312 | const expRange = binding[i];
|
|---|
| 313 | bindingStartLine = encodeInteger(writer, expRange[1]!, bindingStartLine);
|
|---|
| 314 | bindingStartColumn = encodeInteger(writer, expRange[2]!, bindingStartColumn);
|
|---|
| 315 | encodeInteger(writer, expRange[0]!, 0);
|
|---|
| 316 | }
|
|---|
| 317 | }
|
|---|
| 318 | }
|
|---|
| 319 |
|
|---|
| 320 | for (index++; index < ranges.length; ) {
|
|---|
| 321 | const next = ranges[index];
|
|---|
| 322 | const { 0: l, 1: c } = next;
|
|---|
| 323 | if (l > endLine || (l === endLine && c >= endColumn)) {
|
|---|
| 324 | break;
|
|---|
| 325 | }
|
|---|
| 326 | index = _encodeGeneratedRanges(ranges, index, writer, state);
|
|---|
| 327 | }
|
|---|
| 328 |
|
|---|
| 329 | if (state[0] < endLine) {
|
|---|
| 330 | catchupLine(writer, state[0], endLine);
|
|---|
| 331 | state[0] = endLine;
|
|---|
| 332 | state[1] = 0;
|
|---|
| 333 | } else {
|
|---|
| 334 | writer.write(comma);
|
|---|
| 335 | }
|
|---|
| 336 | state[1] = encodeInteger(writer, endColumn, state[1]);
|
|---|
| 337 |
|
|---|
| 338 | return index;
|
|---|
| 339 | }
|
|---|
| 340 |
|
|---|
| 341 | function catchupLine(writer: StringWriter, lastLine: number, line: number) {
|
|---|
| 342 | do {
|
|---|
| 343 | writer.write(semicolon);
|
|---|
| 344 | } while (++lastLine < line);
|
|---|
| 345 | }
|
|---|