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

WIP: Transform for F# Pipeline #1

Conversation

thiagoarrais
Copy link

@thiagoarrais thiagoarrais commented Mar 22, 2019

Q                       A
Fixed Issues?
Patch: Bug Fix?
Major: Breaking Change?
Minor: New Feature? Yes
Tests Added + Pass? Yes
Documentation PR Link
Any Dependency Changes? No
License MIT

This is a transform for the F# proposal of the pipeline operator based on @mAAdhaTTah's parsing code.

It is basically the minimal visitor with support for paramless await. The most relevant lines are fsharpVisitor.js/44-47

TODO:

  • dedup optimization logic between minimal and fsharp
  • integration tests for paren-less arrow functions
  • eliminate temp _ref vars from optimized outputs
  • the name buildOptmizedSequenceExpression is misleading. it returns call expressions sometimes. fix that.

@mAAdhaTTah
Copy link
Owner

Arrow functions don't require parens, so we def need tests to make sure those are transpiled correctly as well.

@thiagoarrais
Copy link
Author

Arrow functions don't require parens, so we def need tests to make sure those are transpiled correctly as well.

Yeah, that would be nice. I'll add some tests on that vein for integration testing purposes. But this is more of a parser concern, in my opinion. It would be nice to cover that more thoroughly in the parser tests.

@mAAdhaTTah
Copy link
Owner

It would be nice to cover that more thoroughly in the parser tests.

I think we've got it covered there, but I'd definitely be more comfortable if I saw the full transform here. We can then address that in the parser if we need to.

@thiagoarrais
Copy link
Author

thiagoarrais commented Mar 25, 2019

Trying to write parenless tests. What should g(1) be here? 2 or 4?

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

@mAAdhaTTah
Copy link
Owner

Yeah, Nicolo pointed out the same issue on the parser PR. I think that's a bug I'll need to address; in the last arrow, y should not be in scope.

@mAAdhaTTah
Copy link
Owner

Oh wait, you're writing this with parens... so that's a different issue.

@mAAdhaTTah
Copy link
Owner

Ping me on slack to discuss this, probably easier that way.

@thiagoarrais
Copy link
Author

Nicolo pointed out the same issue on the parser PR.

Yeah. I stole Nicolo's code from there.

😜

@thiagoarrais
Copy link
Author

Ping me on slack to discuss this

For anyone following this, we've discussed it and came to the conclusion that g(1) should be 2.

Inludes support for optimizing single-parameter arrow functions
@thiagoarrais
Copy link
Author

Updated to latest parser and did the initial clean up. I will port this PR to the main babel repo once the parser PR gets merged.

I still plan on deduping the arrow function optimization logic between this and minimal.

I think we've got it covered there, but I'd definitely be more comfortable if I saw the full transform here. We can then address that in the parser if we need to.

Regarding that, do you think the added test is sufficient to address the concerns you raised?

@mAAdhaTTah
Copy link
Owner

Yeah, this looks great! Thank you so much for working on this.

This is finally happeninggg! Makes me really excited for the possibilities of the proposal itself.

@thiagoarrais
Copy link
Author

Deduped optimization logic between fsharp and minimal. Please let me know what you think.

@thiagoarrais thiagoarrais deleted the transform-f#-pipeline branch April 24, 2019 16:26
@thiagoarrais thiagoarrais restored the transform-f#-pipeline branch April 24, 2019 16:26
@thiagoarrais
Copy link
Author

Oops... Fat-fingered the PR branch. Reopening...

@thiagoarrais thiagoarrais reopened this Apr 24, 2019
@mAAdhaTTah
Copy link
Owner

LGTM! Looking forward to getting this all in place.

const fsharpVisitor = {
BinaryExpression(path) {
const { scope } = path;
const { node } = path;

Choose a reason for hiding this comment

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

Nit: these two statements can be merged

Copy link
Author

Choose a reason for hiding this comment

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

Done in ecbb465

call,
]);
path.replaceWith(sequence);
maybeOptimizePipelineSequence(path);

Choose a reason for hiding this comment

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

Instead of creating a temporary path for the sequence expression and then optimizing it away, would it be possible to do something like this?

path.replaceWith(
  buildOptimizedSequenceExpression({
    assign: t.assignmentExpression("=", t.cloneNode(placeholder), left),
    call,
    path,
  })
);

Copy link
Author

Choose a reason for hiding this comment

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

I started with something similar to this but ended up passing the path in because I needed it for the scope.rename call. I think your approach is doable and would be cleaner. I'll give it a try.

y + 1
|> (z) => z * y);
}
)

Choose a reason for hiding this comment

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

All this random indentation makes it really hard to review this file 😛

Copy link
Author

Choose a reason for hiding this comment

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

It is hard for me too :-p

I'm still getting the hang of how to indent pipelines. I'll see what I can do.

Copy link
Author

Choose a reason for hiding this comment

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

Please see 4811f08 and let me know what you think.

Copy link

Choose a reason for hiding this comment

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

Yeah they look better. As a general rule, I think that if the pipeline body is multiline, ) should aligned with the | of |> and there should be a line break after (. SImilar to

return (
  x => y
);

Let's hope Prettier implements them soon 😛


var inc = x => x + 1;

expect((_ = 10, inc(_))).toBe(11);

Choose a reason for hiding this comment

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

If at least one of the following conditions is true, we could optimize it to inc(10):

  • the right expression is an identifier and it is declared
  • the left expression is immutable

Copy link
Author

Choose a reason for hiding this comment

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

Agreed. Will do.

Copy link
Author

Choose a reason for hiding this comment

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

This also applies to minimal. Right?

Copy link
Author

Choose a reason for hiding this comment

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

Added this in 63b7c04. I'm marking the PR as WIP, though. I'm uncomfortable with buildOptimizedSequenceExpression now no longer returning a sequence expression. And it also does some AST deconstructing that I would like to avoid.

Choose a reason for hiding this comment

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

If you prefer, we can work on this optimization in a separate PR, and keep the current one as it was.

@thiagoarrais thiagoarrais changed the title Transform for F# Pipeline WIP: Transform for F# Pipeline May 9, 2019
@thiagoarrais
Copy link
Author

This was moved to the main repo as babel#9984

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants