Skip to content

Commit

Permalink
Transform for F#-style await
Browse files Browse the repository at this point in the history
Inludes support for optimizing single-parameter arrow functions
  • Loading branch information
thiagoarrais committed Apr 17, 2019
1 parent f34dc8a commit bbb8a14
Show file tree
Hide file tree
Showing 24 changed files with 293 additions and 1 deletion.
@@ -0,0 +1,55 @@
import { types as t } from "@babel/core";

const fsharpVisitor = {
BinaryExpression(path) {
const { scope } = path;
const { node } = path;
const { operator, left } = node;
let { 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);
scope.push({ id: placeholder });
if (param) {
path.get("right").scope.rename(param.name, placeholder.name);
}

const applied =
right.type === "AwaitExpression"
? t.awaitExpression(t.cloneNode(placeholder))
: t.callExpression(right, [t.cloneNode(placeholder)]);
const call = optimizeArrow ? right.body : applied;
path.replaceWith(
t.sequenceExpression([
t.assignmentExpression("=", t.cloneNode(placeholder), left),
call,
]),
);
},
};

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
@@ -0,0 +1,34 @@
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 _sum, _ref, _ref2;

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

var inc = x => x + 1;

var double = x => x * 2;

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

return _ref3 = (_x = x, inc(_x)), double(_ref3);
});
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,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,5 @@
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);
@@ -0,0 +1,23 @@
const y = 2;

const f = x => {
var _z, _y;

return _z = (_y = x, _y + 1), _z * y;
};

const g = x => {
var _y2, _z2;

return _y2 = x, (_z2 = _y2 + 1, _z2 * _y2);
};

const h = x => {
var _y3, _z3;

return _y3 = x, (_z3 = _y3 + 1, _z3 * _y3);
};

expect(f(1)).toBe(4);
expect(g(1)).toBe(2);
expect(h(1)).toBe(2);
@@ -1,6 +1,6 @@
import { declare } from "@babel/helper-plugin-utils";

export const proposals = ["minimal", "smart"];
export const proposals = ["minimal", "smart", "fsharp"];

export default declare((api, { proposal }) => {
api.assertVersion(7);
Expand Down

0 comments on commit bbb8a14

Please sign in to comment.