Skip to content

Commit 3346c07

Browse files
committed
remake else if as repeat($._else_clause)
Before, it looked like this: ``` if ... { } else if let ... = ... { } else if ... { } else { } (if_expression ... consequence: (block) alternative: (else_clause (if_let_expression ... consequence: (block) alternative: (else_clause (if_expression consequence: (block) alternative: (else_clause (block))))))) ``` After, it looks like this: ``` if ... { } else if let ... = ... { } else if ... { } else { } (if_expression condition: ... consequence: (block) (else_if_let_clause pattern: ... value: ... consequence: (block)) (else_if_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 each of the three clause types can only appear in the tail of an if[_let]_expression. And both of the above problems are solved.
1 parent a3e6768 commit 3346c07

File tree

5 files changed

+64829
-62164
lines changed

5 files changed

+64829
-62164
lines changed

corpus/expressions.txt

Lines changed: 51 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,10 @@ If expressions
332332
============================================
333333

334334
fn main() {
335+
if n == 2 {
336+
}
335337
if n == 1 {
338+
} else if let Some(k) = z {
336339
} else if n == 2 {
337340
} else {
338341
}
@@ -348,28 +351,60 @@ let y = if x == 5 { 10 } else { 15 };
348351
parameters: (parameters)
349352
body: (block
350353
(if_expression
351-
condition: (binary_expression
352-
left: (identifier)
353-
right: (integer_literal))
354+
condition: (binary_expression left: (identifier) right: (integer_literal))
355+
consequence: (block))
356+
(if_expression
357+
condition: (binary_expression left: (identifier) right: (integer_literal))
354358
consequence: (block)
355-
alternative: (else_clause
356-
(if_expression
357-
condition: (binary_expression
358-
left: (identifier)
359-
right: (integer_literal))
360-
consequence: (block)
361-
alternative: (else_clause (block)))))))
359+
(else_if_let_clause
360+
pattern: (tuple_struct_pattern type: (identifier) (identifier))
361+
value: (identifier)
362+
consequence: (block))
363+
(else_if_clause
364+
condition: (binary_expression left: (identifier) right: (integer_literal))
365+
consequence: (block))
366+
(else_clause (block)))))
362367
(let_declaration
363368
pattern: (identifier)
364369
value: (if_expression
365-
condition: (binary_expression
366-
left: (identifier)
367-
right: (integer_literal))
370+
condition: (binary_expression left: (identifier) right: (integer_literal))
368371
consequence: (block (integer_literal))
369-
alternative: (else_clause (block (integer_literal))))))
372+
(else_clause (block (integer_literal))))))
373+
374+
============================================
375+
If let as an expression
376+
============================================
377+
378+
let x = if let Some(a) = dish {
379+
a
380+
} else if let None = dish {
381+
99
382+
} else if n == 8 {
383+
9
384+
} else {
385+
7
386+
};
387+
388+
---
389+
390+
(source_file
391+
(let_declaration
392+
pattern: (identifier)
393+
value: (if_let_expression
394+
pattern: (tuple_struct_pattern type: (identifier) (identifier))
395+
value: (identifier)
396+
consequence: (block (identifier))
397+
(else_if_let_clause
398+
pattern: (identifier)
399+
value: (identifier)
400+
consequence: (block (integer_literal)))
401+
(else_if_clause
402+
condition: (binary_expression left: (identifier) right: (integer_literal))
403+
consequence: (block (integer_literal)))
404+
(else_clause (block (integer_literal))))))
370405

371406
============================================
372-
If let expressions
407+
If let control flow
373408
============================================
374409

375410
if let ("Bacon", b) = dish {
@@ -798,7 +833,7 @@ let three_ranges = [const { (0..=5).into_inner() }; 3];
798833
field: (field_identifier))
799834
arguments: (arguments
800835
(integer_literal)))))))
801-
alternative: (else_clause
836+
(else_clause
802837
(block
803838
(identifier))))
804839
(let_declaration

grammar.js

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ module.exports = grammar({
5454
$._literal_pattern,
5555
$._declaration_statement,
5656
$._pattern,
57+
$._else_clause,
5758
],
5859

5960
inline: $ => [
@@ -1069,7 +1070,7 @@ module.exports = grammar({
10691070
'if',
10701071
field('condition', $._expression),
10711072
field('consequence', $.block),
1072-
optional(field("alternative", $.else_clause))
1073+
repeat($._else_clause),
10731074
),
10741075

10751076
if_let_expression: $ => seq(
@@ -1079,16 +1080,35 @@ module.exports = grammar({
10791080
'=',
10801081
field('value', $._expression),
10811082
field('consequence', $.block),
1082-
optional(field('alternative', $.else_clause))
1083+
repeat($._else_clause),
1084+
),
1085+
1086+
_else_clause: $ => choice(
1087+
$.else_if_clause,
1088+
$.else_if_let_clause,
1089+
$.else_clause,
1090+
),
1091+
1092+
else_if_clause: $ => seq(
1093+
'else',
1094+
'if',
1095+
field('condition', $._expression),
1096+
field('consequence', $.block),
1097+
),
1098+
1099+
else_if_let_clause: $ => seq(
1100+
'else',
1101+
'if',
1102+
'let',
1103+
field('pattern', $._pattern),
1104+
'=',
1105+
field('value', $._expression),
1106+
field('consequence', $.block),
10831107
),
10841108

10851109
else_clause: $ => seq(
10861110
'else',
1087-
choice(
1088-
$.block,
1089-
$.if_expression,
1090-
$.if_let_expression
1091-
)
1111+
$.block,
10921112
),
10931113

10941114
match_expression: $ => seq(

src/grammar.json

Lines changed: 105 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -6190,20 +6190,11 @@
61906190
}
61916191
},
61926192
{
6193-
"type": "CHOICE",
6194-
"members": [
6195-
{
6196-
"type": "FIELD",
6197-
"name": "alternative",
6198-
"content": {
6199-
"type": "SYMBOL",
6200-
"name": "else_clause"
6201-
}
6202-
},
6203-
{
6204-
"type": "BLANK"
6205-
}
6206-
]
6193+
"type": "REPEAT",
6194+
"content": {
6195+
"type": "SYMBOL",
6196+
"name": "_else_clause"
6197+
}
62076198
}
62086199
]
62096200
},
@@ -6247,20 +6238,102 @@
62476238
}
62486239
},
62496240
{
6250-
"type": "CHOICE",
6251-
"members": [
6252-
{
6253-
"type": "FIELD",
6254-
"name": "alternative",
6255-
"content": {
6256-
"type": "SYMBOL",
6257-
"name": "else_clause"
6258-
}
6259-
},
6260-
{
6261-
"type": "BLANK"
6262-
}
6263-
]
6241+
"type": "REPEAT",
6242+
"content": {
6243+
"type": "SYMBOL",
6244+
"name": "_else_clause"
6245+
}
6246+
}
6247+
]
6248+
},
6249+
"_else_clause": {
6250+
"type": "CHOICE",
6251+
"members": [
6252+
{
6253+
"type": "SYMBOL",
6254+
"name": "else_if_clause"
6255+
},
6256+
{
6257+
"type": "SYMBOL",
6258+
"name": "else_if_let_clause"
6259+
},
6260+
{
6261+
"type": "SYMBOL",
6262+
"name": "else_clause"
6263+
}
6264+
]
6265+
},
6266+
"else_if_clause": {
6267+
"type": "SEQ",
6268+
"members": [
6269+
{
6270+
"type": "STRING",
6271+
"value": "else"
6272+
},
6273+
{
6274+
"type": "STRING",
6275+
"value": "if"
6276+
},
6277+
{
6278+
"type": "FIELD",
6279+
"name": "condition",
6280+
"content": {
6281+
"type": "SYMBOL",
6282+
"name": "_expression"
6283+
}
6284+
},
6285+
{
6286+
"type": "FIELD",
6287+
"name": "consequence",
6288+
"content": {
6289+
"type": "SYMBOL",
6290+
"name": "block"
6291+
}
6292+
}
6293+
]
6294+
},
6295+
"else_if_let_clause": {
6296+
"type": "SEQ",
6297+
"members": [
6298+
{
6299+
"type": "STRING",
6300+
"value": "else"
6301+
},
6302+
{
6303+
"type": "STRING",
6304+
"value": "if"
6305+
},
6306+
{
6307+
"type": "STRING",
6308+
"value": "let"
6309+
},
6310+
{
6311+
"type": "FIELD",
6312+
"name": "pattern",
6313+
"content": {
6314+
"type": "SYMBOL",
6315+
"name": "_pattern"
6316+
}
6317+
},
6318+
{
6319+
"type": "STRING",
6320+
"value": "="
6321+
},
6322+
{
6323+
"type": "FIELD",
6324+
"name": "value",
6325+
"content": {
6326+
"type": "SYMBOL",
6327+
"name": "_expression"
6328+
}
6329+
},
6330+
{
6331+
"type": "FIELD",
6332+
"name": "consequence",
6333+
"content": {
6334+
"type": "SYMBOL",
6335+
"name": "block"
6336+
}
62646337
}
62656338
]
62666339
},
@@ -6272,21 +6345,8 @@
62726345
"value": "else"
62736346
},
62746347
{
6275-
"type": "CHOICE",
6276-
"members": [
6277-
{
6278-
"type": "SYMBOL",
6279-
"name": "block"
6280-
},
6281-
{
6282-
"type": "SYMBOL",
6283-
"name": "if_expression"
6284-
},
6285-
{
6286-
"type": "SYMBOL",
6287-
"name": "if_let_expression"
6288-
}
6289-
]
6348+
"type": "SYMBOL",
6349+
"name": "block"
62906350
}
62916351
]
62926352
},
@@ -8348,7 +8408,8 @@
83488408
"_literal",
83498409
"_literal_pattern",
83508410
"_declaration_statement",
8351-
"_pattern"
8411+
"_pattern",
8412+
"_else_clause"
83528413
]
83538414
}
83548415

0 commit comments

Comments
 (0)