Amend RFC 2175 to support for loops and leading vert by Centril · Pull Request #2530 · rust-lang/rfcs (original) (raw)

In full agreement wrt. style recommendations :)

That said, @Centril, can you please show how this simplifies the grammar enough to be worthwhile?

Certainly! Here goes a review of grammatical simplifications:

The status quo (i.e. with RFC 2071) is that we have (formulated for maximum clarity):

// Important bits:

let_pat : pat ('|' pat)* ;
match_pat : '|'? let_pat ;
for_pat : pat ;

// Where they are used:

expr_if_let : IF LET let_pat '=' expr '{' block '}' else_tail ? ;
expr_while_let : maybe_label WHILE LET let_pat '=' expr '{' block '}' ;
let : LET let_pat maybe_ty_ascription maybe_init_expr ';' ;

expr_for : maybe_label FOR for_pat IN expr_nostruct block ;

match_arm : maybe_outer_attrs match_pat (IF expr_nostruct)? FAT_ARROW ;

// Details of `match ... { .. }`:

expr_match : MATCH expr_nostruct '{' match_clause* nonblock_match_clause? '}' ;
match_clause : nonblock_match_clause ',' | block_match_clause ','? ;
nonblock_match_clause : match_arm (nonblock_expr | block_expr_dot) ;
block_match_clause : match_arm (block | block_expr) ;

what this PR does is unify first bits of the grammar so that we get:

let_pat   : '|'? pat ('|' pat)* ;
match_pat : '|'? pat ('|' pat)* ;
for_pat   : '|'? pat ('|' pat)* ;

since these are all equivalent, our grammar becomes just:

pats_or : '|'? pat ('|' pat)* ;

expr_if_let : IF LET pats_or '=' expr '{' block '}' else_tail ? ;
expr_while_let : maybe_label WHILE LET pats_or '=' expr '{' block '}' ;
let : LET pats_or maybe_ty_ascription maybe_init_expr ';' ;

expr_for : maybe_label FOR pats_or IN expr_nostruct block ;

match_arm : maybe_outer_attrs pats_or (IF expr_nostruct)? FAT_ARROW ;

// as before...

I would not call this simplification drastic, but it is simplification that makes the language have less corner cases and thus makes it easier for users to understand. Another benefit is that macros in particular have an easier time when you avoid syntactic corner cases.

As a note about style, observe that rustfmt already will convert:

match foo { | A => {}, | B => {}, | C => {}, }

into:

match foo { A => {}, B => {}, C => {}, }

The rustfmt tool should, for consistency, apply this rule for any leading | whether it be for match, if let, while let, let, for.