Skip to content

Commit

Permalink
Use a WeakMap to associate indexes to Positions until we decide wheth…
Browse files Browse the repository at this point in the history
…er to make index an actual property in the next minor release.

Reviewed by @tolmasky.
  • Loading branch information
tolmasky committed Jan 17, 2022
1 parent 3b29841 commit 5b4d55d
Show file tree
Hide file tree
Showing 9 changed files with 58 additions and 31 deletions.
7 changes: 4 additions & 3 deletions packages/babel-parser/src/parser/error.js
@@ -1,6 +1,6 @@
// @flow
/* eslint sort-keys: "error" */
import { type Position } from "../util/location";
import { type Position, indexes } from "../util/location";
import CommentsParser from "./comments";
import { type ErrorCode, ErrorCodes } from "./error-codes";
import { type Node } from "../types";
Expand Down Expand Up @@ -111,7 +111,8 @@ export default class ParserError extends CommentsParser {
{ code, template }: ErrorTemplate,
...params: any
): Error | empty {
const pos = loc.index;
// $FlowIgnore[incompatible-type] We know this exists, so it can't be undefined.
const pos: number = indexes.get(loc);
const message =
template.replace(/%(\d+)/g, (_, i: number) => params[i]) +
` (${loc.line}:${loc.column})`;
Expand All @@ -138,7 +139,7 @@ export default class ParserError extends CommentsParser {
errorTemplate: string,
...params: any
): Error | empty {
const pos = loc.index;
const pos = indexes.get(loc);
const message =
errorTemplate.replace(/%(\d+)/g, (_, i: number) => params[i]) +
` (${loc.line}:${loc.column})`;
Expand Down
17 changes: 12 additions & 5 deletions packages/babel-parser/src/parser/expression.js
Expand Up @@ -44,7 +44,11 @@ import {
isIdentifierStart,
canBeReservedWord,
} from "../util/identifier";
import { Position, createPositionWithColumnOffset } from "../util/location";
import {
indexes,
Position,
createPositionWithColumnOffset,
} from "../util/location";
import * as charCodes from "charcodes";
import {
BIND_OUTSIDE,
Expand Down Expand Up @@ -313,13 +317,15 @@ export default class ExpressionParser extends LValParser {

if (
refExpressionErrors.doubleProtoLoc != null &&
refExpressionErrors.doubleProtoLoc.index >= startPos
// $FlowIgnore[incompatible-type] We know this exists, so it can't be undefined.
indexes.get(refExpressionErrors.doubleProtoLoc) >= startPos
) {
refExpressionErrors.doubleProtoLoc = null; // reset because double __proto__ is valid in assignment expression
}
if (
refExpressionErrors.shorthandAssignLoc != null &&
refExpressionErrors.shorthandAssignLoc.index >= startPos
// $FlowIgnore[incompatible-type] We know this exists, so it can't be undefined.
indexes.get(refExpressionErrors.shorthandAssignLoc) >= startPos
) {
refExpressionErrors.shorthandAssignLoc = null; // reset because shorthand default was used correctly
}
Expand Down Expand Up @@ -912,7 +918,7 @@ export default class ExpressionParser extends LValParser {
return (
base.type === "Identifier" &&
base.name === "async" &&
this.state.lastTokEndLoc.index === base.end &&
indexes.get(this.state.lastTokEndLoc) === base.end &&
!this.canInsertSemicolon() &&
// check there are no escape sequences, such as \u{61}sync
base.end - base.start === 5 &&
Expand Down Expand Up @@ -1764,7 +1770,8 @@ export default class ExpressionParser extends LValParser {
this.takeSurroundingComments(
val,
startPos,
this.state.lastTokEndLoc.index,
// $FlowIgnore[incompatible-type] We know this exists, so it can't be undefined.
indexes.get(this.state.lastTokEndLoc),
);

return val;
Expand Down
11 changes: 6 additions & 5 deletions packages/babel-parser/src/parser/node.js
Expand Up @@ -2,7 +2,7 @@

import type Parser from "./index";
import UtilParser from "./util";
import { SourceLocation, type Position } from "../util/location";
import { indexes, type Position, SourceLocation } from "../util/location";
import type { Comment, Node as NodeType, NodeBase } from "../types";

// Start an AST node, attaching a start offset.
Expand Down Expand Up @@ -126,9 +126,9 @@ export class NodeUtils extends UtilParser {
);
}
node.type = type;
node.end = endLoc.index;
node.end = indexes.get(endLoc);
node.loc.end = endLoc;
if (this.options.ranges) node.range[1] = endLoc.index;
if (this.options.ranges) node.range[1] = node.end;
if (this.options.attachComment) this.processComment(node);
return node;
}
Expand All @@ -143,9 +143,10 @@ export class NodeUtils extends UtilParser {
node: NodeBase,
endLoc?: Position = this.state.lastTokEndLoc,
): void {
node.end = endLoc.index;
// $FlowIgnore[incompatible-type] We know this exists, so it can't be undefined.
node.end = indexes.get(endLoc);
node.loc.end = endLoc;
if (this.options.ranges) node.range[1] = endLoc.index;
if (this.options.ranges) node.range[1] = node.end;
}

/**
Expand Down
7 changes: 4 additions & 3 deletions packages/babel-parser/src/parser/util.js
@@ -1,6 +1,6 @@
// @flow

import { type Position } from "../util/location";
import { indexes, type Position } from "../util/location";
import {
tokenIsLiteralPropertyName,
tokenLabelName,
Expand Down Expand Up @@ -120,7 +120,7 @@ export default class UtilParser extends Tokenizer {

hasPrecedingLineBreak(): boolean {
return lineBreak.test(
this.input.slice(this.state.lastTokEndLoc.index, this.state.start),
this.input.slice(indexes.get(this.state.lastTokEndLoc), this.state.start),
);
}

Expand Down Expand Up @@ -152,7 +152,8 @@ export default class UtilParser extends Tokenizer {

// Throws if the current token and the prev one are separated by a space.
assertNoSpace(message: string = "Unexpected space."): void {
if (this.state.start > this.state.lastTokEndLoc.index) {
// $FlowIgnore[incompatible-type] We know this exists, so it can't be undefined.
if (this.state.start > indexes.get(this.state.lastTokEndLoc)) {
/* eslint-disable @babel/development-internal/dry-error-messages */
this.raise(
{
Expand Down
4 changes: 2 additions & 2 deletions packages/babel-parser/src/plugins/flow/index.js
Expand Up @@ -17,7 +17,7 @@ import {
tokenIsFlowInterfaceOrTypeOrOpaque,
} from "../../tokenizer/types";
import * as N from "../../types";
import { Position } from "../../util/location";
import { indexes, Position } from "../../util/location";
import { types as tc } from "../../tokenizer/context";
import * as charCodes from "charcodes";
import { isIteratorStart } from "../../util/identifier";
Expand Down Expand Up @@ -269,7 +269,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
this.next(); // eat `%`
this.expectContextual(tt._checks);
// Force '%' and 'checks' to be adjacent
if (this.state.lastTokStart > moduloLoc.index + 1) {
if (this.state.lastTokStart > indexes.get(moduloLoc) + 1) {
this.raise(FlowErrors.UnexpectedSpaceBetweenModuloChecks, {
at: moduloLoc,
});
Expand Down
5 changes: 3 additions & 2 deletions packages/babel-parser/src/plugins/jsx/index.js
Expand Up @@ -18,7 +18,7 @@ import {
import { TokContext, types as tc } from "../../tokenizer/context";
import * as N from "../../types";
import { isIdentifierChar, isIdentifierStart } from "../../util/identifier";
import type { Position } from "../../util/location";
import { indexes, type Position } from "../../util/location";
import { isNewLine } from "../../util/whitespace";
import { Errors, makeErrorTemplates, ErrorCodes } from "../../parser/error";

Expand Down Expand Up @@ -327,7 +327,8 @@ export default (superClass: Class<Parser>): Class<Parser> =>

jsxParseEmptyExpression(): N.JSXEmptyExpression {
const node = this.startNodeAt(
this.state.lastTokEndLoc.index,
// $FlowIgnore[incompatible-type] We know this exists, so it can't be undefined.
indexes.get(this.state.lastTokEndLoc),
this.state.lastTokEndLoc,
);
return this.finishNodeAt(node, "JSXEmptyExpression", this.state.startLoc);
Expand Down
17 changes: 12 additions & 5 deletions packages/babel-parser/src/tokenizer/index.js
Expand Up @@ -3,7 +3,11 @@
/*:: declare var invariant; */

import type { Options } from "../options";
import { Position, createPositionWithColumnOffset } from "../util/location";
import {
indexes,
Position,
createPositionWithColumnOffset,
} from "../util/location";
import * as N from "../types";
import * as charCodes from "charcodes";
import { isIdentifierStart, isIdentifierChar } from "../util/identifier";
Expand Down Expand Up @@ -1249,7 +1253,7 @@ export default class Tokenizer extends ParserErrors {

if (isBigInt) {
const str = this.input
.slice(startLoc.index, this.state.pos)
.slice(indexes.get(startLoc), this.state.pos)
.replace(/[_n]/g, "");
this.finishToken(tt.bigint, str);
return;
Expand Down Expand Up @@ -1494,10 +1498,12 @@ export default class Tokenizer extends ParserErrors {
}

recordStrictModeErrors(message: ErrorTemplate, loc: Position) {
if (this.state.strict && !this.state.strictErrors.has(loc.index)) {
// $FlowIgnore[incompatible-type] We know this exists, so it can't be undefined.
const index: number = indexes.get(loc);
if (this.state.strict && !this.state.strictErrors.has(index)) {
this.raise(message, { at: loc });
} else {
this.state.strictErrors.set(loc.index, { loc, message });
this.state.strictErrors.set(index, { loc, message });
}
}

Expand Down Expand Up @@ -1607,7 +1613,8 @@ export default class Tokenizer extends ParserErrors {
if (throwOnInvalid) {
this.raise(Errors.InvalidEscapeSequence, { at: codeLoc });
} else {
this.state.pos = codeLoc.index - 1;
// $FlowIgnore[incompatible-type] We know this exists, so it can't be undefined.
this.state.pos = indexes.get(codeLoc) - 1;
}
}
return n;
Expand Down
8 changes: 5 additions & 3 deletions packages/babel-parser/src/util/expression-scope.js
@@ -1,7 +1,7 @@
// @flow

import type { ErrorData, ErrorTemplate, raiseFunction } from "../parser/error";
import { Position } from "./location";
import { indexes, Position } from "./location";

/*:: declare var invariant; */
/**
Expand Down Expand Up @@ -80,10 +80,12 @@ class ArrowHeadParsingScope extends ExpressionScope {
super(type);
}
recordDeclarationError(message: ErrorTemplate, loc: Position) {
this.errors.set(loc.index, { message, loc });
// $FlowIgnore[incompatible-type] We know this exists, so it can't be undefined.
this.errors.set(indexes.get(loc), { message, loc });
}
clearDeclarationError(loc: Position) {
this.errors.delete(loc.index);
// $FlowIgnore[incompatible-type] We know this exists, so it can't be undefined.
this.errors.delete(indexes.get(loc));
}
iterateErrors(iterator: (data: ErrorData) => void) {
this.errors.forEach(iterator);
Expand Down
13 changes: 10 additions & 3 deletions packages/babel-parser/src/util/location.js
Expand Up @@ -17,7 +17,8 @@ export class Position {
this.column = col;

// this.index = index;
Object.defineProperty(this, "index", { enumerable: false, value: index });
// Object.defineProperty(this, "index", { enumerable: false, value: index });
indexes.set(this, index);
}
}

Expand All @@ -34,6 +35,8 @@ export class SourceLocation {
}
}

export const indexes: WeakMap<Position, number> = new WeakMap();

/**
* creates a new position with a non-zero column offset from the given position.
* This function should be only be used when we create AST node out of the token
Expand All @@ -49,6 +52,10 @@ export function createPositionWithColumnOffset(
position: Position,
columnOffset: number,
) {
const { line, column, index } = position;
return new Position(line, column + columnOffset, index + columnOffset);
const { line, column } = position;
return new Position(
line,
column + columnOffset,
indexes.get(position) + columnOffset,
);
}

0 comments on commit 5b4d55d

Please sign in to comment.