Skip to content

Commit

Permalink
Fix flow
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolo-ribaudo committed Jan 18, 2019
1 parent a7f22ad commit 1abfbe2
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 21 deletions.
4 changes: 2 additions & 2 deletions packages/babel-parser/src/parser/statement.js
Original file line number Diff line number Diff line change
Expand Up @@ -712,7 +712,7 @@ export default class StatementParser extends ExpressionParser {
parseExpressionStatement(
node: N.ExpressionStatement,
expr: N.Expression,
): N.ExpressionStatement {
): N.Statement {
node.expression = expr;
this.semicolon();
return this.finishNode(node, "ExpressionStatement");
Expand Down Expand Up @@ -1043,7 +1043,7 @@ export default class StatementParser extends ExpressionParser {
);
}

parseClassBody(): void {
parseClassBody(): N.ClassBody {
this.state.classLevel++;

const state = { hadConstructor: false };
Expand Down
5 changes: 4 additions & 1 deletion packages/babel-parser/src/plugin-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,4 +98,7 @@ export const mixinPlugins: { [name: string]: MixinPlugin } = {
typescript,
placeholders,
};
export const mixinPluginNames = Object.keys(mixinPlugins);

export const mixinPluginNames: $ReadOnlyArray<string> = Object.keys(
mixinPlugins,
);
77 changes: 61 additions & 16 deletions packages/babel-parser/src/plugins/placeholders.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,50 @@ import * as N from "../types";

tt.placeholder = new TokenType("%%", { startsExpr: true });

export type PlaceholderTypes =
| "Identifier"
| "StringLiteral"
| "Expression"
| "Statement"
| "Declaration"
| "BlockStatement"
| "ClassBody"
| "Pattern";

// $PropertyType doesn't support enums. Use a fake "switch" (GetPlaceholderNode)
//type MaybePlaceholder<T: PlaceholderTypes> = $PropertyType<N, T> | N.Placeholder<T>;

type _Switch<Value, Cases, Index> = $Call<
(
$ElementType<$ElementType<Cases, Index>, 0>,
) => $ElementType<$ElementType<Cases, Index>, 1>,
Value,
>;
type $Switch<Value, Cases> = _Switch<Value, Cases, *>;

type NodeOf<T: PlaceholderTypes> = $Switch<
T,
[
["Identifier", N.Identifier],
["StringLiteral", N.StringLiteral],
["Expression", N.Expression],
["Statement", N.Statement],
["Declaration", N.Declaration],
["BlockStatement", N.BlockStatement],
["ClassBody", N.ClassBody],
["Pattern", N.Pattern],
],
>;

// Placeholder<T> breaks everything, because its type is incompatible with
// the substituted nodes.
type MaybePlaceholder<T: PlaceholderTypes> = NodeOf<T>; // | Placeholder<T>

export default (superClass: Class<Parser>): Class<Parser> =>
class extends superClass {
parsePlaceholder(expectedNode: string): ?N.Placeholder {
parsePlaceholder<T: PlaceholderTypes>(
expectedNode: T,
): /*?N.Placeholder<T>*/ ?MaybePlaceholder<T> {
if (this.match(tt.placeholder)) {
const node = this.startNode();
this.next();
Expand All @@ -26,7 +67,10 @@ export default (superClass: Class<Parser>): Class<Parser> =>
}
}

finishPlaceholder(node: N.Node, expectedNode: string): N.Placeholder {
finishPlaceholder<T: PlaceholderTypes>(
node: N.Node,
expectedNode: T,
): /*N.Placeholder<T>*/ MaybePlaceholder<T> {
node.expectedNode = expectedNode;
return this.finishNode(node, "Placeholder");
}
Expand All @@ -50,13 +94,13 @@ export default (superClass: Class<Parser>): Class<Parser> =>
* parser/expression.js *
* ============================================================ */

parseExprAtom(): N.Expression | N.Placeholder {
parseExprAtom(): MaybePlaceholder<"Expression"> {
return (
this.parsePlaceholder("Expression") || super.parseExprAtom(...arguments)
);
}

parseIdentifier(): N.Identifier | N.Placeholder {
parseIdentifier(): MaybePlaceholder<"Identifier"> {
// NOTE: This function only handles identifiers outside of
// expressions and binding patterns, since they are already
// handled by the parseExprAtom and parseBindingAtom functions.
Expand All @@ -78,7 +122,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
* parser/lval.js *
* ============================================================ */

parseBindingAtom(): N.Pattern | N.Placeholder {
parseBindingAtom(): MaybePlaceholder<"Pattern"> {
return (
this.parsePlaceholder("Pattern") || super.parseBindingAtom(...arguments)
);
Expand All @@ -88,7 +132,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
if (expr.type !== "Placeholder") super.checkLVal(...arguments);
}

toAssignable(node: Node): Node {
toAssignable(node: N.Node): N.Node {
if (
node &&
node.type === "Placeholder" &&
Expand All @@ -110,9 +154,9 @@ export default (superClass: Class<Parser>): Class<Parser> =>
}

parseExpressionStatement(
node: N.Node,
node: MaybePlaceholder<"Statement">,
expr: N.Expression,
): N.Statement | N.Placeholder {
): MaybePlaceholder<"Statement"> {
if (
expr.type !== "Placeholder" ||
(expr.extra && expr.extra.parenthesized)
Expand All @@ -121,32 +165,33 @@ export default (superClass: Class<Parser>): Class<Parser> =>
}

if (this.match(tt.colon)) {
node.label = this.finishPlaceholder(expr, "Identifier");
const stmt: N.LabeledStatement = node;
stmt.label = this.finishPlaceholder(expr, "Identifier");
this.next();
node.body = this.parseStatement(true);
return this.finishNode(node, "LabeledStatement");
stmt.body = this.parseStatement(true);
return this.finishNode(stmt, "LabeledStatement");
}

this.semicolon();
return this.finishPlaceholder(node, "Statement");
}

parseBlock(): N.BlockStatement | N.Placeholder {
parseBlock(): MaybePlaceholder<"BlockStatement"> {
return (
this.parsePlaceholder("BlockStatement") ||
super.parseBlock(...arguments)
);
}

parseFunctionId(): ?N.Identifier | N.Placeholder {
parseFunctionId(): ?MaybePlaceholder<"Identifier"> {
return (
this.parsePlaceholder("Identifier") ||
super.parseFunctionId(...arguments)
);
}

parseClass(
node: N.Class,
parseClass<T: N.Class>(
node: T,
isStatement: /* T === ClassDeclaration */ boolean,
optionalId?: boolean,
): T {
Expand Down Expand Up @@ -254,7 +299,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
return this.finishNode(node, "ImportDeclaration");
}

parseImportSource(): N.StringLiteral | N.Placeholder {
parseImportSource(): MaybePlaceholder<"StringLiteral"> {
// import ... from %%STRING%%;

return (
Expand Down
11 changes: 9 additions & 2 deletions packages/babel-parser/src/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import type { SourceType } from "./options";
import type { Token } from "./tokenizer";
import type { SourceLocation } from "./util/location";
import type { PlaceholderTypes } from "./plugins/placeholders";

/*
* If making any changes to the AST, update:
Expand Down Expand Up @@ -45,6 +46,7 @@ export type Pattern =
| ArrayPattern
| RestElement
| AssignmentPattern;
//| Placeholder<"Pattern">;
export type Declaration =
| VariableDeclaration
| ClassDeclaration
Expand All @@ -53,6 +55,8 @@ export type Declaration =
| TsTypeAliasDeclaration
| TsEnumDeclaration
| TsModuleDeclaration;
// | Placeholder<"Declaration">;

export type DeclarationBase = NodeBase & {
// TypeScript allows declarations to be prefixed by `declare`.
//TODO: a FunctionDeclaration is never "declare", because it's a TSDeclareFunction instead.
Expand All @@ -78,6 +82,7 @@ export type Identifier = PatternBase & {
// TypeScript only. Used in case of an optional parameter.
optional?: ?true,
};
// | Placeholder<"Identifier">;

export type PrivateName = NodeBase & {
type: "PrivateName",
Expand Down Expand Up @@ -188,6 +193,7 @@ export type BlockStatement = NodeBase & {
body: Array<Statement>, // TODO: $ReadOnlyArray
directives: $ReadOnlyArray<Directive>,
};
// | Placeholder<"BlockStatement">;

export type EmptyStatement = NodeBase & {
type: "EmptyStatement",
Expand Down Expand Up @@ -680,6 +686,7 @@ export type ClassBody = NodeBase & {
type: "ClassBody",
body: Array<ClassMember | TsIndexSignature>, // TODO: $ReadOnlyArray
};
// | Placeholder<"ClassBody">;

export type ClassMemberBase = NodeBase &
HasDecorators & {
Expand Down Expand Up @@ -1420,10 +1427,10 @@ export type TsNonNullExpression = NodeBase & {
// Babel placeholders %%foo%%
// ================

export type Placeholder = NodeBase & {
export type Placeholder<N: PlaceholderTypes> = NodeBase & {
type: "Placeholder",
id: Identifier,
expectedNode: string,
expectedNode: N,
};

// ================
Expand Down

0 comments on commit 1abfbe2

Please sign in to comment.