Skip to content

Commit

Permalink
Implement f# pipeline in parser (#9450)
Browse files Browse the repository at this point in the history
  • Loading branch information
mAAdhaTTah authored and nicolo-ribaudo committed May 14, 2019
1 parent 1969e6b commit d6c39ee
Show file tree
Hide file tree
Showing 54 changed files with 4,295 additions and 19 deletions.
92 changes: 75 additions & 17 deletions packages/babel-parser/src/parser/expression.js
Expand Up @@ -331,8 +331,11 @@ export default class ExpressionParser extends LValParser {
const prec = this.state.type.binop;
if (prec != null && (!noIn || !this.match(tt._in))) {
if (prec > minPrec) {
const node = this.startNodeAt(leftStartPos, leftStartLoc);
const operator = this.state.value;
if (operator === "|>" && this.state.inFSharpPipelineDirectBody) {
return left;
}
const node = this.startNodeAt(leftStartPos, leftStartLoc);
node.left = left;
node.operator = operator;
if (
Expand Down Expand Up @@ -406,18 +409,23 @@ export default class ExpressionParser extends LValParser {
prec: number,
noIn: ?boolean,
): N.Expression {
const startPos = this.state.start;
const startLoc = this.state.startLoc;
switch (op) {
case tt.pipeline:
if (this.getPluginOption("pipelineOperator", "proposal") === "smart") {
const startPos = this.state.start;
const startLoc = this.state.startLoc;
return this.withTopicPermittingContext(() => {
return this.parseSmartPipelineBody(
this.parseExprOpBaseRightExpr(op, prec, noIn),
startPos,
startLoc,
);
});
switch (this.getPluginOption("pipelineOperator", "proposal")) {
case "smart":
return this.withTopicPermittingContext(() => {
return this.parseSmartPipelineBody(
this.parseExprOpBaseRightExpr(op, prec, noIn),
startPos,
startLoc,
);
});
case "fsharp":
return this.withSoloAwaitPermittingContext(() => {
return this.parseFSharpPipelineBody(prec, noIn);
});
}
// falls through

Expand Down Expand Up @@ -766,6 +774,8 @@ export default class ExpressionParser extends LValParser {
const elts = [];
let innerParenStart;
let first = true;
const oldInFSharpPipelineDirectBody = this.state.inFSharpPipelineDirectBody;
this.state.inFSharpPipelineDirectBody = false;

while (!this.eat(close)) {
if (first) {
Expand Down Expand Up @@ -804,6 +814,8 @@ export default class ExpressionParser extends LValParser {
this.unexpected();
}

this.state.inFSharpPipelineDirectBody = oldInFSharpPipelineDirectBody;

return elts;
}

Expand Down Expand Up @@ -969,7 +981,10 @@ export default class ExpressionParser extends LValParser {
case tt.parenL:
return this.parseParenAndDistinguishExpression(canBeArrow);

case tt.bracketL:
case tt.bracketL: {
const oldInFSharpPipelineDirectBody = this.state
.inFSharpPipelineDirectBody;
this.state.inFSharpPipelineDirectBody = false;
node = this.startNode();
this.next();
node.elements = this.parseExprList(
Expand All @@ -985,11 +1000,17 @@ export default class ExpressionParser extends LValParser {
// expression by calling toReferencedListDeep.
this.toReferencedList(node.elements);
}
this.state.inFSharpPipelineDirectBody = oldInFSharpPipelineDirectBody;
return this.finishNode(node, "ArrayExpression");

case tt.braceL:
return this.parseObj(false, refShorthandDefaultPos);

}
case tt.braceL: {
const oldInFSharpPipelineDirectBody = this.state
.inFSharpPipelineDirectBody;
this.state.inFSharpPipelineDirectBody = false;
const ret = this.parseObj(false, refShorthandDefaultPos);
this.state.inFSharpPipelineDirectBody = oldInFSharpPipelineDirectBody;
return ret;
}
case tt._function:
return this.parseFunctionExpression();

Expand Down Expand Up @@ -1180,9 +1201,11 @@ export default class ExpressionParser extends LValParser {
const oldMaybeInArrowParameters = this.state.maybeInArrowParameters;
const oldYieldPos = this.state.yieldPos;
const oldAwaitPos = this.state.awaitPos;
const oldInFSharpPipelineDirectBody = this.state.inFSharpPipelineDirectBody;
this.state.maybeInArrowParameters = true;
this.state.yieldPos = 0;
this.state.awaitPos = 0;
this.state.inFSharpPipelineDirectBody = false;

const innerStartPos = this.state.start;
const innerStartLoc = this.state.startLoc;
Expand Down Expand Up @@ -1236,6 +1259,7 @@ export default class ExpressionParser extends LValParser {
this.expect(tt.parenR);

this.state.maybeInArrowParameters = oldMaybeInArrowParameters;
this.state.inFSharpPipelineDirectBody = oldInFSharpPipelineDirectBody;

let arrowNode = this.startNodeAt(startPos, startLoc);
if (
Expand Down Expand Up @@ -2117,7 +2141,9 @@ export default class ExpressionParser extends LValParser {
);
}

node.argument = this.parseMaybeUnary();
if (!this.state.soloAwait) {
node.argument = this.parseMaybeUnary();
}
return this.finishNode(node, "AwaitExpression");
}

Expand Down Expand Up @@ -2307,6 +2333,17 @@ export default class ExpressionParser extends LValParser {
}
}

withSoloAwaitPermittingContext<T>(callback: () => T): T {
const outerContextSoloAwaitState = this.state.soloAwait;
this.state.soloAwait = true;

try {
return callback();
} finally {
this.state.soloAwait = outerContextSoloAwaitState;
}
}

// Register the use of a primary topic reference (`#`) within the current
// topic context.
registerTopicReference(): void {
Expand All @@ -2323,4 +2360,25 @@ export default class ExpressionParser extends LValParser {
this.state.topicContext.maxTopicIndex >= 0
);
}

parseFSharpPipelineBody(prec: number, noIn: ?boolean): N.Expression {
const startPos = this.state.start;
const startLoc = this.state.startLoc;

this.state.potentialArrowAt = this.state.start;
const oldInFSharpPipelineDirectBody = this.state.inFSharpPipelineDirectBody;
this.state.inFSharpPipelineDirectBody = true;

const ret = this.parseExprOp(
this.parseMaybeUnary(),
startPos,
startLoc,
prec,
noIn,
);

this.state.inFSharpPipelineDirectBody = oldInFSharpPipelineDirectBody;

return ret;
}
}
2 changes: 1 addition & 1 deletion packages/babel-parser/src/plugin-utils.js
Expand Up @@ -38,7 +38,7 @@ export function getPluginOption(
return null;
}

const PIPELINE_PROPOSALS = ["minimal", "smart"];
const PIPELINE_PROPOSALS = ["minimal", "smart", "fsharp"];

export function validatePlugins(plugins: PluginList) {
if (hasPlugin(plugins, "decorators")) {
Expand Down
4 changes: 4 additions & 0 deletions packages/babel-parser/src/tokenizer/state.js
Expand Up @@ -77,6 +77,10 @@ export default class State {
maxTopicIndex: null,
};

// For the F# plugin
soloAwait: boolean = false;
inFSharpPipelineDirectBody: boolean = false;

// Check whether we are in a (nested) class or not.
classLevel: number = 0;

Expand Down
@@ -1,4 +1,4 @@
{
"plugins": [["pipelineOperator", { "proposal": "invalid" }]],
"throws": "'pipelineOperator' requires 'proposal' option whose value should be one of: 'minimal', 'smart'"
"throws": "'pipelineOperator' requires 'proposal' option whose value should be one of: 'minimal', 'smart', 'fsharp'"
}
@@ -0,0 +1 @@
x => x |> [y => y + 1 |> z => z * 2]
@@ -0,0 +1,3 @@
{
"plugins": [["pipelineOperator", { "proposal": "fsharp" }]]
}

0 comments on commit d6c39ee

Please sign in to comment.