Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(parser): remove refNeedsArrowPos #13419

Merged
63 changes: 26 additions & 37 deletions packages/babel-parser/src/parser/expression.js
Expand Up @@ -30,7 +30,6 @@ import {
isIdentifierStart,
canBeReservedWord,
} from "../util/identifier";
import type { Pos } from "../util/location";
import { Position } from "../util/location";
import * as charCodes from "charcodes";
import {
Expand All @@ -44,6 +43,7 @@ import {
SCOPE_PROGRAM,
} from "../util/scopeflags";
import { ExpressionErrors } from "./util";
import type { EnrichedSyntaxError } from "./util";
import {
PARAM_AWAIT,
PARAM_IN,
Expand Down Expand Up @@ -222,40 +222,40 @@ export default class ExpressionParser extends LValParser {
parseMaybeAssignDisallowIn(
refExpressionErrors?: ?ExpressionErrors,
afterLeftParse?: Function,
refNeedsArrowPos?: ?Pos,
) {
return this.disallowInAnd(() =>
this.parseMaybeAssign(
refExpressionErrors,
afterLeftParse,
refNeedsArrowPos,
),
this.parseMaybeAssign(refExpressionErrors, afterLeftParse),
);
}

// Set [+In] parameter for assignment expression
parseMaybeAssignAllowIn(
refExpressionErrors?: ?ExpressionErrors,
afterLeftParse?: Function,
refNeedsArrowPos?: ?Pos,
) {
return this.allowInAnd(() =>
this.parseMaybeAssign(
refExpressionErrors,
afterLeftParse,
refNeedsArrowPos,
),
this.parseMaybeAssign(refExpressionErrors, afterLeftParse),
);
}

// Parse an assignment expression. This includes applications of
// operators like `+=`.
tony-go marked this conversation as resolved.
Show resolved Hide resolved

setOptionalParametersError(
tony-go marked this conversation as resolved.
Show resolved Hide resolved
refExpressionErrors: ExpressionErrors,
resultError?: ?EnrichedSyntaxError,
) {
if (resultError && resultError.pos) {
refExpressionErrors.optionalParameters = resultError.pos;
} else {
refExpressionErrors.optionalParameters = this.state.start;
}
tony-go marked this conversation as resolved.
Show resolved Hide resolved
}

// https://tc39.es/ecma262/#prod-AssignmentExpression
parseMaybeAssign(
refExpressionErrors?: ?ExpressionErrors,
afterLeftParse?: Function,
refNeedsArrowPos?: ?Pos,
): N.Expression {
const startPos = this.state.start;
const startLoc = this.state.startLoc;
Expand Down Expand Up @@ -285,10 +285,7 @@ export default class ExpressionParser extends LValParser {
this.state.potentialArrowAt = this.state.start;
}

let left = this.parseMaybeConditional(
refExpressionErrors,
refNeedsArrowPos,
);
let left = this.parseMaybeConditional(refExpressionErrors);
if (afterLeftParse) {
left = afterLeftParse.call(this, left, startPos, startLoc);
}
Expand Down Expand Up @@ -323,10 +320,7 @@ export default class ExpressionParser extends LValParser {
// Parse a ternary conditional (`?:`) operator.
// https://tc39.es/ecma262/#prod-ConditionalExpression

parseMaybeConditional(
refExpressionErrors: ExpressionErrors,
refNeedsArrowPos?: ?Pos,
): N.Expression {
parseMaybeConditional(refExpressionErrors: ExpressionErrors): N.Expression {
const startPos = this.state.start;
const startLoc = this.state.startLoc;
const potentialArrowAt = this.state.potentialArrowAt;
Expand All @@ -336,16 +330,15 @@ export default class ExpressionParser extends LValParser {
return expr;
}

return this.parseConditional(expr, startPos, startLoc, refNeedsArrowPos);
return this.parseConditional(expr, startPos, startLoc, refExpressionErrors);
}

parseConditional(
expr: N.Expression,
startPos: number,
startLoc: Position,
// FIXME: Disabling this for now since can't seem to get it to play nicely
// eslint-disable-next-line no-unused-vars
refNeedsArrowPos?: ?Pos,
refExpressionErrors?: ?ExpressionErrors,
): N.Expression {
if (this.eat(tt.question)) {
const node = this.startNodeAt(startPos, startLoc);
Expand Down Expand Up @@ -935,12 +928,7 @@ export default class ExpressionParser extends LValParser {
}

elts.push(
this.parseExprListItem(
false,
refExpressionErrors,
{ start: 0 },
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Q: refNeedsArrowPos is reset here. Do we need to reset refExpressionErrors.optionalParameters to -1? Maybe worth a test covering this.

allowPlaceholder,
),
this.parseExprListItem(false, refExpressionErrors, allowPlaceholder),
);
}

Expand Down Expand Up @@ -1466,7 +1454,6 @@ export default class ExpressionParser extends LValParser {
const innerStartLoc = this.state.startLoc;
const exprList = [];
const refExpressionErrors = new ExpressionErrors();
const refNeedsArrowPos = { start: 0 };
let first = true;
let spreadStart;
let optionalCommaStart;
Expand All @@ -1475,7 +1462,12 @@ export default class ExpressionParser extends LValParser {
if (first) {
first = false;
} else {
this.expect(tt.comma, refNeedsArrowPos.start || null);
this.expect(
tt.comma,
refExpressionErrors.optionalParameters === -1
? null
: refExpressionErrors.optionalParameters,
);
if (this.match(tt.parenR)) {
optionalCommaStart = this.state.start;
break;
Expand All @@ -1502,7 +1494,6 @@ export default class ExpressionParser extends LValParser {
this.parseMaybeAssignAllowIn(
refExpressionErrors,
this.parseParenItem,
refNeedsArrowPos,
),
);
}
Expand Down Expand Up @@ -1534,7 +1525,6 @@ export default class ExpressionParser extends LValParser {
if (optionalCommaStart) this.unexpected(optionalCommaStart);
if (spreadStart) this.unexpected(spreadStart);
this.checkExpressionErrors(refExpressionErrors, true);
if (refNeedsArrowPos.start) this.unexpected(refNeedsArrowPos.start);

this.toReferencedListDeep(exprList, /* isParenthesizedExpr */ true);
if (exprList.length > 1) {
Expand Down Expand Up @@ -2296,7 +2286,6 @@ export default class ExpressionParser extends LValParser {
parseExprListItem(
allowEmpty: ?boolean,
refExpressionErrors?: ?ExpressionErrors,
refNeedsArrowPos: ?Pos,
allowPlaceholder: ?boolean,
): ?N.Expression {
let elt;
Expand All @@ -2308,6 +2297,7 @@ export default class ExpressionParser extends LValParser {
} else if (this.match(tt.ellipsis)) {
const spreadNodeStartPos = this.state.start;
const spreadNodeStartLoc = this.state.startLoc;
const refNeedsArrowPos = { start: 0 };
tony-go marked this conversation as resolved.
Show resolved Hide resolved
elt = this.parseParenItem(
this.parseSpread(refExpressionErrors, refNeedsArrowPos),
spreadNodeStartPos,
Expand All @@ -2325,7 +2315,6 @@ export default class ExpressionParser extends LValParser {
elt = this.parseMaybeAssignAllowIn(
refExpressionErrors,
this.parseParenItem,
refNeedsArrowPos,
);
}
return elt;
Expand Down
20 changes: 16 additions & 4 deletions packages/babel-parser/src/parser/util.js
Expand Up @@ -26,6 +26,8 @@ type TryParse<Node, Error, Thrown, Aborted, FailState> = {
failState: FailState,
};

export type EnrichedSyntaxError = SyntaxError & { pos?: ?number };

// ## Parser utilities

export default class UtilParser extends Tokenizer {
Expand Down Expand Up @@ -175,9 +177,9 @@ export default class UtilParser extends Tokenizer {
template: `Unexpected token, expected "${messageOrType.label}"`,
};
}

/* eslint-disable @babel/development-internal/dry-error-messages */
throw this.raise(pos != null ? pos : this.state.start, messageOrType);
/* eslint-enable @babel/development-internal/dry-error-messages */
tony-go marked this conversation as resolved.
Show resolved Hide resolved
}

expectPlugin(name: string, pos?: ?number): true {
Expand Down Expand Up @@ -211,7 +213,7 @@ export default class UtilParser extends Tokenizer {
oldState: State = this.state.clone(),
):
| TryParse<T, null, false, false, null>
| TryParse<T | null, SyntaxError, boolean, false, State>
tony-go marked this conversation as resolved.
Show resolved Hide resolved
| TryParse<T | null, EnrichedSyntaxError, boolean, false, State>
| TryParse<T | null, null, false, true, State> {
const abortSignal: { node: T | null } = { node: null };
try {
Expand Down Expand Up @@ -267,14 +269,22 @@ export default class UtilParser extends Tokenizer {
andThrow: boolean,
) {
if (!refExpressionErrors) return false;
const { shorthandAssign, doubleProto } = refExpressionErrors;
if (!andThrow) return shorthandAssign >= 0 || doubleProto >= 0;
const { shorthandAssign, doubleProto, optionalParameters } =
refExpressionErrors;
if (!andThrow) {
return (
shorthandAssign >= 0 || doubleProto >= 0 || optionalParameters >= 0
);
}
if (shorthandAssign >= 0) {
this.unexpected(shorthandAssign);
}
if (doubleProto >= 0) {
this.raise(doubleProto, Errors.DuplicateProto);
}
if (optionalParameters >= 0) {
this.unexpected(optionalParameters);
}
}

/**
Expand Down Expand Up @@ -407,4 +417,6 @@ export default class UtilParser extends Tokenizer {
export class ExpressionErrors {
shorthandAssign = -1;
doubleProto = -1;
//
optionalParameters = -1;
tony-go marked this conversation as resolved.
Show resolved Hide resolved
}
29 changes: 10 additions & 19 deletions packages/babel-parser/src/plugins/flow/index.js
Expand Up @@ -8,7 +8,7 @@
import type Parser from "../../parser";
import { types as tt, type TokenType } from "../../tokenizer/types";
import * as N from "../../types";
import type { Pos, Position } from "../../util/location";
import type { Position } from "../../util/location";
import { types as tc } from "../../tokenizer/context";
import * as charCodes from "charcodes";
import { isIteratorStart, isKeyword } from "../../util/identifier";
Expand Down Expand Up @@ -1910,20 +1910,22 @@ export default (superClass: Class<Parser>): Class<Parser> =>
expr: N.Expression,
startPos: number,
startLoc: Position,
refNeedsArrowPos?: ?Pos,
refExpressionErrors?: ?ExpressionErrors,
): N.Expression {
if (!this.match(tt.question)) return expr;

// only use the expensive "tryParse" method if there is a question mark
// and if we come from inside parens
if (refNeedsArrowPos) {
if (this.state.maybeInArrowParameters) {
const result = this.tryParse(() =>
super.parseConditional(expr, startPos, startLoc),
);

if (!result.node) {
// $FlowIgnore
refNeedsArrowPos.start = result.error.pos || this.state.start;
if (refExpressionErrors) {
tony-go marked this conversation as resolved.
Show resolved Hide resolved
super.setOptionalParametersError(refExpressionErrors, result.error);
}

return expr;
}

Expand Down Expand Up @@ -1977,7 +1979,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
node.test = expr;
node.consequent = consequent;
node.alternate = this.forwardNoArrowParamsConversionAt(node, () =>
this.parseMaybeAssign(undefined, undefined, undefined),
this.parseMaybeAssign(undefined, undefined),
);

return this.finishNode(node, "ConditionalExpression");
Expand Down Expand Up @@ -2824,7 +2826,6 @@ export default (superClass: Class<Parser>): Class<Parser> =>
parseMaybeAssign(
refExpressionErrors?: ?ExpressionErrors,
afterLeftParse?: Function,
refNeedsArrowPos?: ?Pos,
): N.Expression {
let state = null;

Expand All @@ -2837,12 +2838,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
state = this.state.clone();

jsx = this.tryParse(
() =>
super.parseMaybeAssign(
refExpressionErrors,
afterLeftParse,
refNeedsArrowPos,
),
() => super.parseMaybeAssign(refExpressionErrors, afterLeftParse),
state,
);
/*:: invariant(!jsx.aborted) */
Expand Down Expand Up @@ -2874,7 +2870,6 @@ export default (superClass: Class<Parser>): Class<Parser> =>
const result = super.parseMaybeAssign(
refExpressionErrors,
afterLeftParse,
refNeedsArrowPos,
);

this.resetStartLocationFromNode(result, typeParameters);
Expand Down Expand Up @@ -2954,11 +2949,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
);
}

return super.parseMaybeAssign(
refExpressionErrors,
afterLeftParse,
refNeedsArrowPos,
);
return super.parseMaybeAssign(refExpressionErrors, afterLeftParse);
}

// handle return types for arrow functions
Expand Down
14 changes: 8 additions & 6 deletions packages/babel-parser/src/plugins/typescript/index.js
Expand Up @@ -10,7 +10,7 @@ import type State from "../../tokenizer/state";
import { types as tt } from "../../tokenizer/types";
import { types as ct } from "../../tokenizer/context";
import * as N from "../../types";
import type { Pos, Position } from "../../util/location";
import type { Position } from "../../util/location";
import type Parser from "../../parser";
import {
type BindingTypes,
Expand Down Expand Up @@ -2452,16 +2452,16 @@ export default (superClass: Class<Parser>): Class<Parser> =>
expr: N.Expression,
startPos: number,
startLoc: Position,
refNeedsArrowPos?: ?Pos,
refExpressionErrors?: ?ExpressionErrors,
): N.Expression {
// only do the expensive clone if there is a question mark
// and if we come from inside parens
if (!refNeedsArrowPos || !this.match(tt.question)) {
if (!this.state.maybeInArrowParameters || !this.match(tt.question)) {
return super.parseConditional(
expr,
startPos,
startLoc,
refNeedsArrowPos,
refExpressionErrors,
);
}

Expand All @@ -2470,8 +2470,10 @@ export default (superClass: Class<Parser>): Class<Parser> =>
);

if (!result.node) {
// $FlowIgnore
refNeedsArrowPos.start = result.error.pos || this.state.start;
if (refExpressionErrors) {
super.setOptionalParametersError(refExpressionErrors, result.error);
}

return expr;
}
if (result.error) this.state = result.failState;
Expand Down