Skip to content

Commit 6ebdb1d

Browse files
Implement let_chains. (#152)
* Implement let_chains. Instead of a separate `if_let_expression` construct, we make `if_expression` hold multiple `condition`s, each of which can be a `let_condition`. This also applies to `while let` and `match` pattern guards. * Create a separate let_chain node for &&-chains involving let_conditions * Un-name the children of `let_chain` * Avoid unnecessary conflict between let_chain and condition * Avoid conflict for binary expressions within if expressions Co-authored-by: Max Brunsfeld <[email protected]>
1 parent a6e1a62 commit 6ebdb1d

File tree

6 files changed

+63177
-65943
lines changed

6 files changed

+63177
-65943
lines changed

corpus/expressions.txt

+127-11
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,10 @@ fn main() {
489489

490490
let y = if x == 5 { 10 } else { 15 };
491491

492+
if foo && bar {}
493+
494+
if foo && bar || baz {}
495+
492496
--------------------------------------------------------------------------------
493497

494498
(source_file
@@ -520,7 +524,52 @@ let y = if x == 5 { 10 } else { 15 };
520524
(integer_literal))
521525
alternative: (else_clause
522526
(block
523-
(integer_literal))))))
527+
(integer_literal)))))
528+
(expression_statement
529+
(if_expression
530+
condition: (binary_expression
531+
left: (identifier)
532+
right: (identifier))
533+
consequence: (block)))
534+
(expression_statement
535+
(if_expression
536+
condition: (binary_expression
537+
left: (binary_expression
538+
left: (identifier)
539+
right: (identifier))
540+
right: (identifier))
541+
consequence: (block))))
542+
543+
================================================================================
544+
Basic if let expressions
545+
================================================================================
546+
547+
if let Some(a) = b
548+
&& c
549+
&& d
550+
&& let Some(e) = f
551+
{
552+
}
553+
554+
--------------------------------------------------------------------------------
555+
556+
(source_file
557+
(expression_statement
558+
(if_expression
559+
condition: (let_chain
560+
(let_condition
561+
pattern: (tuple_struct_pattern
562+
type: (identifier)
563+
(identifier))
564+
value: (identifier))
565+
(identifier)
566+
(identifier)
567+
(let_condition
568+
pattern: (tuple_struct_pattern
569+
type: (identifier)
570+
(identifier))
571+
value: (identifier)))
572+
consequence: (block))))
524573

525574
================================================================================
526575
If let expressions
@@ -529,16 +578,65 @@ If let expressions
529578
if let ("Bacon", b) = dish {
530579
}
531580

581+
if let Some("chained") = a && b && let (C, D) = e {
582+
}
583+
584+
if foo && let bar = || baz && quux {}
585+
586+
if a && let b = || c || d && e {}
587+
532588
--------------------------------------------------------------------------------
533589

534590
(source_file
535591
(expression_statement
536-
(if_let_expression
537-
(tuple_pattern
538-
(string_literal)
539-
(identifier))
540-
(identifier)
541-
(block))))
592+
(if_expression
593+
condition: (let_condition
594+
pattern: (tuple_pattern
595+
(string_literal)
596+
(identifier))
597+
value: (identifier))
598+
consequence: (block)))
599+
(expression_statement
600+
(if_expression
601+
condition: (let_chain
602+
(let_condition
603+
pattern: (tuple_struct_pattern
604+
type: (identifier)
605+
(string_literal))
606+
value: (identifier))
607+
(identifier)
608+
(let_condition
609+
pattern: (tuple_pattern
610+
(identifier)
611+
(identifier))
612+
value: (identifier)))
613+
consequence: (block)))
614+
(expression_statement
615+
(if_expression
616+
condition: (let_chain
617+
(identifier)
618+
(let_condition
619+
pattern: (identifier)
620+
value: (closure_expression
621+
parameters: (closure_parameters)
622+
body: (binary_expression
623+
left: (identifier)
624+
right: (identifier)))))
625+
consequence: (block)))
626+
(expression_statement
627+
(if_expression
628+
condition: (let_chain
629+
(identifier)
630+
(let_condition
631+
pattern: (identifier)
632+
value: (closure_expression
633+
parameters: (closure_parameters)
634+
body: (binary_expression
635+
left: (identifier)
636+
right: (binary_expression
637+
left: (identifier)
638+
right: (identifier))))))
639+
consequence: (block))))
542640

543641
================================================================================
544642
While let expressions
@@ -551,11 +649,12 @@ while let ("Bacon", b) = dish {
551649

552650
(source_file
553651
(expression_statement
554-
(while_let_expression
555-
(tuple_pattern
556-
(string_literal)
652+
(while_expression
653+
(let_condition
654+
(tuple_pattern
655+
(string_literal)
656+
(identifier))
557657
(identifier))
558-
(identifier)
559658
(block))))
560659

561660
================================================================================
@@ -581,6 +680,7 @@ let msg = match x {
581680
if a {
582681
"200 (but this is not very stylish)"
583682
}
683+
y if let Some(z) = foo && z && let Some(w) = bar => "very chained",
584684
_ => "something else",
585685
};
586686

@@ -657,6 +757,22 @@ let msg = match x {
657757
condition: (identifier)
658758
consequence: (block
659759
(string_literal))))
760+
(match_arm
761+
pattern: (match_pattern
762+
(identifier)
763+
condition: (let_chain
764+
(let_condition
765+
pattern: (tuple_struct_pattern
766+
type: (identifier)
767+
(identifier))
768+
value: (identifier))
769+
(identifier)
770+
(let_condition
771+
pattern: (tuple_struct_pattern
772+
type: (identifier)
773+
(identifier))
774+
value: (identifier))))
775+
value: (string_literal))
660776
(match_arm
661777
pattern: (match_pattern)
662778
value: (string_literal))))))

corpus/patterns.txt

+30-27
Original file line numberDiff line numberDiff line change
@@ -255,31 +255,33 @@ if let x!() | y!() = () {}
255255

256256
(source_file
257257
(expression_statement
258-
(if_let_expression
259-
pattern: (or_pattern
260-
(tuple_struct_pattern
261-
type: (identifier)
262-
(identifier))
263-
(tuple_struct_pattern
264-
type: (identifier)
265-
(identifier)))
266-
value: (identifier)
258+
(if_expression
259+
condition: (let_condition
260+
pattern: (or_pattern
261+
(tuple_struct_pattern
262+
type: (identifier)
263+
(identifier))
264+
(tuple_struct_pattern
265+
type: (identifier)
266+
(identifier)))
267+
value: (identifier))
267268
consequence: (block
268269
(expression_statement
269270
(call_expression
270271
function: (identifier)
271272
arguments: (arguments
272273
(identifier)))))))
273274
(expression_statement
274-
(while_let_expression
275-
pattern: (or_pattern
276-
(tuple_struct_pattern
277-
type: (identifier)
278-
(identifier))
279-
(tuple_struct_pattern
280-
type: (identifier)
281-
(identifier)))
282-
value: (identifier)
275+
(while_expression
276+
condition: (let_condition
277+
pattern: (or_pattern
278+
(tuple_struct_pattern
279+
type: (identifier)
280+
(identifier))
281+
(tuple_struct_pattern
282+
type: (identifier)
283+
(identifier)))
284+
value: (identifier))
283285
body: (block
284286
(expression_statement
285287
(call_expression
@@ -369,15 +371,16 @@ if let x!() | y!() = () {}
369371
type: (primitive_type)))
370372
body: (block))
371373
(expression_statement
372-
(if_let_expression
373-
pattern: (or_pattern
374-
(macro_invocation
375-
macro: (identifier)
376-
(token_tree))
377-
(macro_invocation
378-
macro: (identifier)
379-
(token_tree)))
380-
value: (unit_expression)
374+
(if_expression
375+
condition: (let_condition
376+
pattern: (or_pattern
377+
(macro_invocation
378+
macro: (identifier)
379+
(token_tree))
380+
(macro_invocation
381+
macro: (identifier)
382+
(token_tree)))
383+
value: (unit_expression))
381384
consequence: (block)))
382385
(line_comment)
383386
(line_comment)

grammar.js

+24-22
Original file line numberDiff line numberDiff line change
@@ -874,10 +874,8 @@ module.exports = grammar({
874874
$.async_block,
875875
$.block,
876876
$.if_expression,
877-
$.if_let_expression,
878877
$.match_expression,
879878
$.while_expression,
880-
$.while_let_expression,
881879
$.loop_expression,
882880
$.for_expression,
883881
$.const_block
@@ -1096,27 +1094,37 @@ module.exports = grammar({
10961094

10971095
if_expression: $ => prec.right(seq(
10981096
'if',
1099-
field('condition', $._expression),
1097+
field('condition', $._condition),
11001098
field('consequence', $.block),
11011099
optional(field("alternative", $.else_clause))
11021100
)),
11031101

1104-
if_let_expression: $ => prec.right(seq(
1105-
'if',
1102+
let_condition: $ => seq(
11061103
'let',
11071104
field('pattern', $._pattern),
11081105
'=',
1109-
field('value', $._expression),
1110-
field('consequence', $.block),
1111-
optional(field('alternative', $.else_clause))
1106+
field('value', prec.left(PREC.and, $._expression))
1107+
),
1108+
1109+
_let_chain: $ => prec.left(PREC.and, choice(
1110+
seq($._let_chain, '&&', $.let_condition),
1111+
seq($._let_chain, '&&', $._expression),
1112+
seq($.let_condition, '&&', $._expression),
1113+
seq($.let_condition, '&&', $.let_condition),
1114+
seq($._expression, '&&', $.let_condition),
11121115
)),
11131116

1117+
_condition: $ => choice(
1118+
$._expression,
1119+
$.let_condition,
1120+
alias($._let_chain, $.let_chain),
1121+
),
1122+
11141123
else_clause: $ => seq(
11151124
'else',
11161125
choice(
11171126
$.block,
1118-
$.if_expression,
1119-
$.if_let_expression
1127+
$.if_expression
11201128
)
11211129
),
11221130

@@ -1155,23 +1163,13 @@ module.exports = grammar({
11551163

11561164
match_pattern: $ => seq(
11571165
$._pattern,
1158-
optional(seq('if', field('condition', $._expression)))
1166+
optional(seq('if', field('condition', $._condition)))
11591167
),
11601168

11611169
while_expression: $ => seq(
11621170
optional(seq($.loop_label, ':')),
11631171
'while',
1164-
field('condition', $._expression),
1165-
field('body', $.block)
1166-
),
1167-
1168-
while_let_expression: $ => seq(
1169-
optional(seq($.loop_label, ':')),
1170-
'while',
1171-
'let',
1172-
field('pattern', $._pattern),
1173-
'=',
1174-
field('value', $._expression),
1172+
field('condition', $._condition),
11751173
field('body', $.block)
11761174
),
11771175

@@ -1479,6 +1477,10 @@ module.exports = grammar({
14791477
}
14801478
})
14811479

1480+
function sepBy2(sep, rule) {
1481+
return seq(rule, repeat1(seq(sep, rule)))
1482+
}
1483+
14821484
function sepBy1(sep, rule) {
14831485
return seq(rule, repeat(seq(sep, rule)))
14841486
}

0 commit comments

Comments
 (0)