-
Notifications
You must be signed in to change notification settings - Fork 104
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
remake else if as repeat($.else_clause) #105
base: master
Are you sure you want to change the base?
Conversation
@maxbrunsfeld what do you think? Should we accept the PR because it helps some indentation tools outside even though it makes the grammar slighly more complicated? What do we do for other languages with a similar elseif structures? |
I'm ok with this change. You're right @aryx that we shouldn't make grammars significantly more complicated in order to support the limitations of specific text editors/tools. Sometimes, a tool just may need to generalize the shapes of syntax trees that it can deal with. But in this case, the added complexity is pretty limited, and we're hearing feedback from multiple consumers of this parser that the proposed tree would be easier to work with. I want to be receptive to that kind of feedback. Thanks everyone for weighing in; it makes it easier to make judgment calls when multiple folks share their experience using the parser. |
Thanks Max and aryx, and thanks everyone else for the discussion. I'll have a quick go at the improvement I alluded to and see if it works, otherwise I'll shape it up for a merge. |
@cormacrelf can you rebase with the latest version to resolve the conflicts and then it should be good to go since max approved it. |
Before, it looked like this: ``` if ... { } else if let ... = ... { } else if ... { } else { } (if_expression condition: ... consequence: (block) alternative: (else_clause (if_expression condition: (let_condition pattern: ... value: ...) consequence: (block) alternative: (else_clause (if_expression condition: ... consequence: (block) alternative: (else_clause (block))))))) ``` After, it looks like this: ``` if ... { } else if let ... = ... { } else if ... { } else { } (if_expression condition: ... consequence: (block) (else_clause condition: (let_condition pattern: ... value: ...) consequence: (block)) (else_clause condition: ... consequence: (block)) (else_clause (block))) ``` Previously, the "else" and "if" were not adjacent tokens, and therefore could not be grouped together in an `("else" "if") @match` query. The main motivation here is highlighting each if/else if/else branch with vim-matchup. It was also difficult to query only a complete if/else expression, and exclude if_expressions that were simply the "if" in an "else if". It is maybe wrong to say that the latter is actually an expression, but moreover if you wanted to query only the former, you would have to either list all the contexts where an if_expression can occur (except else_clause) or use an #if-not? to exclude the `(else_clause (if_expression) @not_this)`. Again, the motivation is attempting to navigate between if/else branches in the editor using vim matchup, which requires matching one single `(if_expression) @scope.if` to link all the branches to, and not creating a bunch of smaller scopes on all the if_expressions contained within. The resulting tree is flatter. There is no need for the alternative: field name as (else_clause) only appears in the tail of an (if_expression) and never at the top level in the condition/consequence, hence writing (else_clause) in a query unambiguously selects nodes at the tail. And the previous two problems are solved: - `(else_clause "else" "if")` can match now, and it will not match a final `else {}` clause. Previously it was an impossible pattern. - `(if_expression)` will only match once in a chain of `if {} else if {} ...`s, with the match over the entire expression. No need for hacky tricks to avoid matches on inner `if_expression`s.
I found this again, sorry I didn't manage to batch this with the recent breaking changes to if expressions to support let-else statements. Notably, the question of whether we wanted else_clause in there is resolved, because those recent changes introduced an There are a couple of outstanding questions, I think:
|
Can you rebase @cormacrelf And for your questions:
|
Motivation: andymass/vim-matchup#140 -- see the query file https://github.com/andymass/vim-matchup/pull/140/files#diff-d74a0aa0bf2225f5b3d440f88938de06c9c0373c035643ba22aed5a34d5ffcc5 for the specific queries.
Before, it looked like this:
After, it looks like this:
Previously, the "else" and "if" were not adjacent tokens, and therefore could not be grouped together in an
("else" "if") @match
query. The main motivation here is highlighting each if/else if/else branch with vim-matchup.It was also difficult to query only a complete if/else expression, and exclude if_expressions that were simply the "if" in an "else if". It is maybe wrong to say that the latter is actually an expression, but moreover if you wanted to query only the former, you would have to either list all the contexts where an if_expression can occur (except else_clause) or use an #if-not? to exclude the
(else_clause (if_expression) @not_this)
. Again, the motivation is attempting to navigate between if/else branches in the editor using vim matchup, which requires matching one single(if_expression) @scope.if
to link all the branches to, and not creating a bunch of smaller scopes on all the if_expressions contained within.The resulting tree is flatter. There is no need for the alternative: field name as (else_clause) only appears in the tail of an
(if_expression) and never at the top level in the condition/consequence, hence writing (else_clause) in a query unambiguously selects nodes at the tail. And the previous two problems are solved:
(else_clause "else" "if")
can match now, and it will not match afinal
else {}
clause. Previously it was an impossible pattern.(if_expression)
will only match once in a chain ofif {} else if {} ...
s, with the match over the entire expression. No need for hackytricks to avoid matches on inner
if_expression
s.