-
Notifications
You must be signed in to change notification settings - Fork 2k
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
[CS2] add parens to chained do IIFE #4666
[CS2] add parens to chained do IIFE #4666
Conversation
src/rewriter.coffee
Outdated
action = (token, i) -> | ||
return unless token[0] is '.' | ||
@tokens.splice doIndex, 0, generate '(', '(', @tokens[doIndex][2] | ||
@tokens.splice i + 1, 0, generate ')', ')', ['', 'implicit parentheses', token[2]] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@GeoffreyBooth @lydell I'm not too sure what these origin args should be?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
origin
is just a reference to whatever token we copied the location data from. So for (
, that should be the do
token, and for )
, that should be whatever token immediately precedes the )
after it's inserted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@GeoffreyBooth ok updated origin args to reference those tokens (I believe)
src/rewriter.coffee
Outdated
condition = (token, i) -> | ||
@tag(i - 1) is 'OUTDENT' | ||
action = (token, i) -> | ||
return unless token[0] is '.' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be token[0] in CALL_CLOSERS
to include ::
etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@GeoffreyBooth updated to in CALL_CLOSERS
and changed one test to use ?.
instead of .
src/rewriter.coffee
Outdated
action = (token, i) -> | ||
return unless token[0] is '.' | ||
@tokens.splice doIndex, 0, generate '(', '(', @tokens[doIndex][2] | ||
@tokens.splice i + 1, 0, generate ')', ')', ['', 'implicit parentheses', token[2]] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
origin
is just a reference to whatever token we copied the location data from. So for (
, that should be the do
token, and for )
, that should be whatever token immediately precedes the )
after it's inserted.
Looks great! @lydell or anyone else want to review? |
One could argue that this belongs in |
This really shouldn't need an extra rewriter rule — it's a sign that we haven't fully thought through the grammatical model. Ideally, there would be a change to the grammar that would make this work instead. |
@jashkenas I thought about that but it looked like at that point you're in the realm of operator precedence. Seemed much more dangerous/sweeping to mess with that rather than just handle this specific case (at least for now) @GeoffreyBooth it seems that way based on naming but |
Well, Personally I think we should get rid of |
I take back the first part of my previous comment. It’s part of the |
@GeoffreyBooth I think this lives on the lexer/rewriter/grammar side of the fence, in And for the record -1 on getting rid of |
Fair enough. I guess maybe it’s a question of style, I very rarely use IIFEs. As for lexer/rewriter/nodes, where is |
Yeah, I often use updateElement = do ->
$element = $ selector
return -> $element.method arg I would actually like CoffeeScript to introduce with jQuery then @ajax args... I'm a bit of a Crockford acolyte, so rarely reference |
Yes. It started out as a keyword, (eg. The rewriter is supposed to only be for syntax that the parser really can't handle. Not things that it can. Edit: Also, I'd be +1 for removing Edit2: Original introduction / reasoning here: #959 |
@jashkenas I feel like the refactor you're describing should be its own PR. Would you be okay with merging this as it is and we can tackle that cleanup separately? |
Sure -- you're calling the shots. Go for it. |
@GeoffreyBooth it looks like it's added in So in theory @jashkenas is right, and
parse as
to parse as
So (at least for now) I don't see why handling this in the rewriter is bad, it's pretty clean as such things go @carlsmith exactly, it's great for "localizing" state needed by a closure like that. And I like the style of that
where |
ah @jashkenas ya if you're comfortable distinguishing But so ya if you guys are good with it I'd say merge this for now and I can plan on tackling it at a grammatical level later (and at that point presumably remove the need for this rewriting) |
@helixbass That's fundamentally what you're doing with this change: Distinguishing The fewer passes over the source code the rewriter has to do, the better. They're one of the more expensive (in terms of compile time) changes you can make. |
Okay, I’m going to merge this in now because most people would consider the #3736 behavior a bug, and this fixes that. Then if we want to refactor, that can be a new PR. I don’t know if that effort needs an issue (other than this one) but feel free to open one if you want a reminder or some way to discuss implementation before submitting a PR. There are other similar features that should probably get some similar refactoring love, like interpolated strings/CSX, or chaining overall; and I might prioritize those more highly than |
This doesn't work when the IIFE has arguments: do (a) ->
a
.b
# (function(a) {
# return a;
# }).b() |
@helixbass - Thanks. Yeah, |
* add parens to chained do iife [Fixes #3736] * remove debug code * fixes from code review * handle iife with params * add test w/ destructured param from code review
Fixes #3736
@GeoffreyBooth this implements the behavior that @darky was looking for in #3736. I think the compilation he wants is almost always what someone would want when chaining after a
do -> ...
(as discussed, the only real use case for chaining off of a function literal (like now enabled by #4665) would seem to be.call()/.apply()
). So I think it's actually sketchy that it currently (post-#4665) unintuitively compiles the chain against the function objectSo now this:
will compile to:
(ie
(do -> a).b
)rather than the current:
(ie
do ((-> a).b)
But behavior for chained
do <non-IIFE>
shouldn't change, ie this:should continue to be treated as
do (a.b)
. This one has bitten me a couple times but I see how both ways could be considered intuitive and I've learned to avoid itSo the added rewriter pass just targets
do
followed by->
or=>
(ie an IIFE) whose body is followed by a.
, and wraps thedo <IIFE>
in parens (added tests for indented and inline function bodies as well as that existing chaineddo <non-IIFE>
behavior is preserved)I think the inconsistency this would introduce of chained
do <IIFE>
vs chaineddo <non-IIFE>
is far outweighed by the unintuitive, non-useful current compilation of chaineddo <IIFE>