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

Transform for F# Pipeline #9984

Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -0,0 +1,50 @@
import { types as t } from "@babel/core";

// tries to optimize sequence expressions in the format
// (a = b, ((c) => d + e)(a))
// to
// (a = b, a + e)
const buildOptimizedSequenceExpression = ({ assign, call, path }) => {
Copy link
Member

Choose a reason for hiding this comment

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

const { left: placeholderNode, right: pipelineLeft } = assign;
const { callee: calledExpression } = call;

let optimizeArrow =
t.isArrowFunctionExpression(calledExpression) &&
t.isExpression(calledExpression.body) &&
!calledExpression.async &&
!calledExpression.generator;
let param;

if (optimizeArrow) {
const { params } = calledExpression;
if (params.length === 1 && t.isIdentifier(params[0])) {
param = params[0];
} else if (params.length > 0) {
optimizeArrow = false;
}
} else if (t.isIdentifier(calledExpression, { name: "eval" })) {
const evalSequence = t.sequenceExpression([
t.numericLiteral(0),
calledExpression,
]);

call.callee = evalSequence;

return t.sequenceExpression([assign, call]);
}

if (optimizeArrow && !param) {
// Arrow function with 0 arguments
return t.sequenceExpression([pipelineLeft, calledExpression.body]);
}

if (param) {
path.get("right").scope.rename(param.name, placeholderNode.name);

return t.sequenceExpression([assign, calledExpression.body]);
}

return t.sequenceExpression([assign, call]);
};

export default buildOptimizedSequenceExpression;
@@ -0,0 +1,26 @@
import { types as t } from "@babel/core";
import buildOptimizedSequenceExpression from "./buildOptimizedSequenceExpression";

const fsharpVisitor = {
BinaryExpression(path) {
const { scope, node } = path;
const { operator, left, right } = node;
if (operator !== "|>") return;

const placeholder = scope.generateUidIdentifierBasedOnNode(left);
scope.push({ id: placeholder });

const call =
right.type === "AwaitExpression"
? t.awaitExpression(t.cloneNode(placeholder))
: t.callExpression(right, [t.cloneNode(placeholder)]);
const sequence = buildOptimizedSequenceExpression({
assign: t.assignmentExpression("=", t.cloneNode(placeholder), left),
call,
path,
});
path.replaceWith(sequence);
},
};

export default fsharpVisitor;
2 changes: 2 additions & 0 deletions packages/babel-plugin-proposal-pipeline-operator/src/index.js
Expand Up @@ -2,10 +2,12 @@ import { declare } from "@babel/helper-plugin-utils";
import syntaxPipelineOperator from "@babel/plugin-syntax-pipeline-operator";
import minimalVisitor from "./minimalVisitor";
import smartVisitor from "./smartVisitor";
import fsharpVisitor from "./fsharpVisitor";

const visitorsPerProposal = {
minimal: minimalVisitor,
smart: smartVisitor,
fsharp: fsharpVisitor,
};

export default declare((api, options) => {
Expand Down
@@ -1,51 +1,22 @@
import { types as t } from "@babel/core";
import buildOptimizedSequenceExpression from "./buildOptimizedSequenceExpression";

const minimalVisitor = {
BinaryExpression(path) {
const { scope } = path;
const { node } = path;
const { operator, left } = node;
let { right } = node;
const { scope, node } = path;
const { operator, left, right } = node;
if (operator !== "|>") return;

let optimizeArrow =
t.isArrowFunctionExpression(right) &&
t.isExpression(right.body) &&
!right.async &&
!right.generator;
let param;

if (optimizeArrow) {
const { params } = right;
if (params.length === 1 && t.isIdentifier(params[0])) {
param = params[0];
} else if (params.length > 0) {
optimizeArrow = false;
}
} else if (t.isIdentifier(right, { name: "eval" })) {
right = t.sequenceExpression([t.numericLiteral(0), right]);
}

if (optimizeArrow && !param) {
// Arrow function with 0 arguments
path.replaceWith(t.sequenceExpression([left, right.body]));
return;
}

const placeholder = scope.generateUidIdentifierBasedOnNode(param || left);
const placeholder = scope.generateUidIdentifierBasedOnNode(left);
scope.push({ id: placeholder });
if (param) {
path.get("right").scope.rename(param.name, placeholder.name);
}

const call = optimizeArrow
? right.body
: t.callExpression(right, [t.cloneNode(placeholder)]);
const call = t.callExpression(right, [t.cloneNode(placeholder)]);
path.replaceWith(
t.sequenceExpression([
t.assignmentExpression("=", t.cloneNode(placeholder), left),
buildOptimizedSequenceExpression({
assign: t.assignmentExpression("=", t.cloneNode(placeholder), left),
call,
]),
path,
}),
);
},
};
Expand Down
@@ -0,0 +1,27 @@
const y = 2;

const f = (x) => (x |> (y) => y + 1)
|> (z) => z * y

const _f = (x) => x
|> (y) => y + 1
|> (z) => z * y

const g = (x) => x
|> (y) => (y + 1 |> (z) => z * y)

const _g = (x) => x
|> (y => (y + 1 |> (z) => z * y))

const __g = (x) => x
|> (
y => {
return (y + 1 |> (z) => z * y);
}
)

expect( f(1)).toBe(4);
expect( _f(1)).toBe(4);
expect( g(1)).toBe(2);
expect( _g(1)).toBe(2);
expect(__g(1)).toBe(2);
@@ -0,0 +1,14 @@
var result = [5,10]
|> (_ => _.map(x => x * 2))
|> (_ => _.reduce( (a,b) => a + b ))
|> (sum => sum + 1)

expect(result).toBe(31);


var inc = (x) => x + 1;
var double = (x) => x * 2;

var result2 = [4, 9].map( x => x |> inc |> double )

expect(result2).toEqual([10, 20]);
@@ -0,0 +1,14 @@
var result = [5,10]
|> (_ => _.map(x => x * 2))
|> (_ => _.reduce( (a,b) => a + b ))
|> (sum => sum + 1)

expect(result).toBe(31);


var inc = (x) => x + 1;
var double = (x) => x * 2;

var result2 = [4, 9].map( x => x |> inc |> double )

expect(result2).toEqual([10, 20]);
@@ -0,0 +1,15 @@
var _ref, _ref2, _ref3;

var result = (_ref = (_ref2 = (_ref3 = [5, 10], _ref3.map(x => x * 2)), _ref2.reduce((a, b) => a + b)), _ref + 1);
expect(result).toBe(31);

var inc = x => x + 1;

var double = x => x * 2;

var result2 = [4, 9].map(x => {
var _ref4, _x;

return _ref4 = (_x = x, inc(_x)), double(_ref4);
});
expect(result2).toEqual([10, 20]);
@@ -0,0 +1,13 @@
const triple = (x) => x * 3;

async function myFunction(n) {
return n
|> Math.abs
|> Promise.resolve
|> await
|> triple;
}

return myFunction(-7).then(result => {
expect(result).toBe(21);
});
@@ -0,0 +1,6 @@
async function myFunction(n) {
return n
|> Math.abs
|> Promise.resolve
|> await;
}
@@ -0,0 +1,9 @@
{
"plugins": [
["proposal-pipeline-operator", { "proposal": "fsharp" }]
],
"parserOpts": {
"allowReturnOutsideFunction": true
},
"minNodeVersion": "8.0.0"
}
@@ -0,0 +1,5 @@
async function myFunction(n) {
var _ref, _ref2, _n;

return _ref = (_ref2 = (_n = n, Math.abs(_n)), Promise.resolve(_ref2)), await _ref;
}
@@ -0,0 +1,3 @@
var inc = (x) => x + 1

expect(10 |> inc).toBe(11);
@@ -0,0 +1,3 @@
var inc = (x) => x + 1

expect(10 |> inc).toBe(11);
@@ -0,0 +1,5 @@
var _;

var inc = x => x + 1;

expect((_ = 10, inc(_))).toBe(11);
@@ -0,0 +1,7 @@
(function() {
'use strict';
var result = '(function() { return this; })()'
|> eval;

expect(result).not.toBeUndefined();
})();
@@ -0,0 +1,7 @@
(function() {
'use strict';
var result = '(function() { return this; })()'
|> eval;

expect(result).not.toBeUndefined();
})();
@@ -0,0 +1,8 @@
(function () {
'use strict';

var _functionReturn;

var result = (_functionReturn = '(function() { return this; })()', (0, eval)(_functionReturn));
expect(result).not.toBeUndefined();
})();
@@ -0,0 +1,5 @@
var array = [10,20,30];

var last = array |> (a => a[a.length-1]);

expect(last).toBe(30);
@@ -0,0 +1,5 @@
var _array;

var array = [10, 20, 30];
var last = (_array = array, _array[_array.length - 1]);
expect(last).toBe(30);
@@ -0,0 +1,8 @@
var a = 1,
b = 2,
c = 3;
var result = a
|> (() => b)
|> (() => c);

expect(result).toBe(c);
@@ -0,0 +1,8 @@
var a = 1,
b = 2,
c = 3;
var result = a
|> (() => b)
|> (() => c);

expect(result).toBe(c);
@@ -0,0 +1,7 @@
var _ref, _a;

var a = 1,
b = 2,
c = 3;
var result = ((a, b), c);
expect(result).toBe(c);
@@ -0,0 +1,8 @@
{
"plugins": [
["proposal-pipeline-operator", { "proposal": "fsharp" }]
],
"parserOpts": {
"allowReturnOutsideFunction": true
}
}
@@ -0,0 +1,20 @@
const y = 2;
const f = (x) => x
|> (y => y + 1)
|> (z => z * y)

const g = (x) => x
|> (y =>
y + 1
|> (z => z * y)
)

const h = (x) => x
|> (y => (
y + 1
|> (z => z * y)
))

expect(f(1)).toBe(4);
expect(g(1)).toBe(2);
expect(h(1)).toBe(2);
@@ -0,0 +1,20 @@
const y = 2;
const f = (x) => x
|> (y => y + 1)
|> (z => z * y)

const g = (x) => x
|> (y =>
y + 1
|> (z => z * y)
)

const h = (x) => x
|> (y => (
y + 1
|> (z => z * y)
))

expect(f(1)).toBe(4);
expect(g(1)).toBe(2);
expect(h(1)).toBe(2);