Skip to content

Commit 75991dd

Browse files
committed
Add support for or-patterns
Rust got full-blown support for or-patterns (see [RFC 2535][0]). This means a couple changes: * `OrP` is a new variant of `Pat` * `WhileLet`, `IfLet`, `Arm` now just take a `Pat` (instead of a list) * in the parser, or-patterns are not allowed everywhere that regular patterns are! Tests cases were heavily inspired by [the PR that implemented the RFC][1]. [0]: https://github.com/rust-lang/rfcs/blob/master/text/2535-or-patterns.md#grammar [1]: rust-lang/rust#63693
1 parent fbf2626 commit 75991dd

File tree

6 files changed

+129
-76
lines changed

6 files changed

+129
-76
lines changed

src/Language/Rust/Parser/Internal.y

+29-21
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ import qualified Data.List.NonEmpty as N
7272
%name parseLit lit
7373
%name parseAttr export_attribute
7474
%name parseTy ty
75-
%name parsePat pat
75+
%name parsePat or_pat
7676
%name parseStmt stmt
7777
%name parseExpr expr
7878
%name parseItem mod_item
@@ -805,6 +805,10 @@ lambda_arg :: { Arg Span }
805805
-- Patterns --
806806
--------------
807807

808+
top_pat :: { Pat Span }
809+
: '|' or_pat { $> }
810+
| or_pat { $> }
811+
808812
-- There is a funky trick going on here around 'IdentP'. When there is a binding mode (ie a 'mut' or
809813
-- 'ref') or an '@' pattern, everything is fine, but otherwise there is no difference between an
810814
-- expression variable path and a pattern. To deal with this, we intercept expression paths with
@@ -831,20 +835,27 @@ pat :: { Pat Span }
831835
| expr_qual_path { PathP (Just (fst (unspan $1))) (snd (unspan $1)) ($1 # $>) }
832836
| lit_or_path '...' lit_or_path { RangeP $1 $3 ($1 # $>) }
833837
| lit_or_path '..=' lit_or_path { RangeP $1 $3 ($1 # $>) }
834-
| expr_path '{' '..' '}' { StructP $1 [] True ($1 # $>) }
835838
| expr_path '{' pat_fields '}' { let (fs,b) = $3 in StructP $1 fs b ($1 # $>) }
836-
| expr_path '(' sep_byT(pat,',') ')' { TupleStructP $1 $3 ($1 # $>) }
839+
| expr_path '(' sep_byT(or_pat,',') ')' { TupleStructP $1 $3 ($1 # $>) }
837840
| expr_mac { MacP $1 (spanOf $1) }
838-
| '[' sep_byT(pat,',') ']' { SliceP $2 ($1 # $>) }
841+
| '[' sep_byT(or_pat,',') ']' { SliceP $2 ($1 # $>) }
839842
| '(' ')' { TupleP [] ($1 # $>) }
840-
| '(' sep_by1(pat,',') ',' ')' { TupleP (toList $2) ($1 # $>) }
841-
| '(' sep_by1(pat,',') ')' {
843+
| '(' sep_by1(or_pat,',') ',' ')' { TupleP (toList $2) ($1 # $>) }
844+
| '(' sep_by1(or_pat,',') ')' {
842845
case toList $2 of
843846
l @ [RestP _] -> TupleP l ($1 # $>) -- (..) is a tuple pattern
844847
[p] -> ParenP p ($1 # $>) -- (<pat>) is parenthesis around a pattern
845848
l -> TupleP l ($1 # $>) -- (<pat1>, <pat2>) is a tuple pattern
846849
}
847850

851+
-- Or-pattern
852+
or_pat :: { Pat Span }
853+
: sep_by1(pat,'|') {
854+
case toNonEmpty $1 of
855+
[p] -> p
856+
ps -> OrP ps (spanOf ps)
857+
}
858+
848859
-- Endpoints of range patterns
849860
lit_or_path :: { Expr Span }
850861
: expr_path { PathExpr [] Nothing $1 (spanOf $1) }
@@ -854,15 +865,16 @@ lit_or_path :: { Expr Span }
854865

855866
-- Used in patterns for expression patterns
856867
pat_fields :: { ([FieldPat Span], Bool) }
857-
: sep_byT(pat_field,',') { ($1, False) }
868+
: '..' { ([], True) }
869+
| sep_byT(pat_field,',') { ($1, False) }
858870
| sep_by1(pat_field,',') ',' '..' { (toList $1, True) }
859871

860872
pat_field :: { FieldPat Span }
861873
: binding_mode ident
862874
{ FieldPat Nothing (IdentP (unspan $1) (unspan $2) Nothing (spanOf $2)) ($1 # $2) }
863875
| box binding_mode ident
864876
{ FieldPat Nothing (BoxP (IdentP (unspan $2) (unspan $3) Nothing ($2 # $3)) ($1 # $3)) ($1 # $3) }
865-
| binding_mode ident ':' pat
877+
| binding_mode ident ':' or_pat
866878
{ FieldPat (Just (unspan $2)) $4 ($1 # $2 # $4) }
867879

868880

@@ -1090,12 +1102,12 @@ block_like_expr :: { Expr Span }
10901102
: if_expr { $1 }
10911103
| loop inner_attrs_block { let (as,b) = $> in Loop as b Nothing ($1 # b) }
10921104
| label ':' loop inner_attrs_block { let (as,b) = $> in Loop as b (Just $1) ($1 # b) }
1093-
| for pat in nostruct_expr inner_attrs_block { let (as,b) = $> in ForLoop as $2 $4 b Nothing ($1 # b) }
1094-
| label ':' for pat in nostruct_expr inner_attrs_block { let (as,b) = $> in ForLoop as $4 $6 b (Just $1) ($1 # b) }
1105+
| for top_pat in nostruct_expr inner_attrs_block { let (as,b) = $> in ForLoop as $2 $4 b Nothing ($1 # b) }
1106+
| label ':' for top_pat in nostruct_expr inner_attrs_block { let (as,b) = $> in ForLoop as $4 $6 b (Just $1) ($1 # b) }
10951107
| while nostruct_expr inner_attrs_block { let (as,b) = $> in While as $2 b Nothing ($1 # b) }
10961108
| label ':' while nostruct_expr inner_attrs_block { let (as,b) = $> in While as $4 b (Just $1) ($1 # b) }
1097-
| while let pats '=' nostruct_expr inner_attrs_block { let (as,b) = $> in WhileLet as $3 $5 b Nothing ($1 # b) }
1098-
| label ':' while let pats '=' nostruct_expr inner_attrs_block { let (as,b) = $> in WhileLet as $5 $7 b (Just $1) ($1 # b) }
1109+
| while let top_pat '=' nostruct_expr inner_attrs_block { let (as,b) = $> in WhileLet as $3 $5 b Nothing ($1 # b) }
1110+
| label ':' while let top_pat '=' nostruct_expr inner_attrs_block { let (as,b) = $> in WhileLet as $5 $7 b (Just $1) ($1 # b) }
10991111
| match nostruct_expr '{' '}' { Match [] $2 [] ($1 # $>) }
11001112
| match nostruct_expr '{' inner_attrs '}' { Match (toList $4) $2 [] ($1 # $>) }
11011113
| match nostruct_expr '{' arms '}' { Match [] $2 $4 ($1 # $>) }
@@ -1107,8 +1119,8 @@ block_like_expr :: { Expr Span }
11071119

11081120
-- 'if' expressions are a bit special since they can have an arbitrary number of 'else if' chains.
11091121
if_expr :: { Expr Span }
1110-
: if nostruct_expr block else_expr { If [] $2 $3 $4 ($1 # $3 # $>) }
1111-
| if let pats '=' nostruct_expr block else_expr { IfLet [] $3 $5 $6 $7 ($1 # $6 # $>) }
1122+
: if nostruct_expr block else_expr { If [] $2 $3 $4 ($1 # $3 # $>) }
1123+
| if let top_pat '=' nostruct_expr block else_expr { IfLet [] $3 $5 $6 $7 ($1 # $6 # $>) }
11121124

11131125
else_expr :: { Maybe (Expr Span) }
11141126
: else block { Just (BlockExpr [] $2 (spanOf $2)) }
@@ -1120,11 +1132,7 @@ else_expr :: { Maybe (Expr Span) }
11201132
arms :: { [Arm Span] }
11211133
: ntArm { [$1] }
11221134
| ntArm arms { $1 : $2 }
1123-
| many(outer_attribute) pats arm_guard '=>' expr_arms { let (e,as) = $> in (Arm $1 $2 $3 e ($1 # $2 # e) : as) }
1124-
1125-
pats :: { NonEmpty (Pat Span) }
1126-
: '|' sep_by1(pat,'|') { toNonEmpty $2 }
1127-
| sep_by1(pat,'|') { toNonEmpty $1 }
1135+
| many(outer_attribute) top_pat arm_guard '=>' expr_arms { let (e,as) = $> in (Arm $1 $2 $3 e ($1 # $2 # e) : as) }
11281136

11291137
arm_guard :: { Maybe (Expr Span) }
11301138
: {- empty -} { Nothing }
@@ -1224,8 +1232,8 @@ union_default_expr :: { Expr Span }
12241232
12251233
stmt :: { Stmt Span }
12261234
: ntStmt { $1 }
1227-
| many(outer_attribute) let pat ':' ty initializer ';' { Local $3 (Just $5) $6 $1 ($1 # $2 # $>) }
1228-
| many(outer_attribute) let pat initializer ';' { Local $3 Nothing $4 $1 ($1 # $2 # $>) }
1235+
| many(outer_attribute) let top_pat ':' ty initializer ';' { Local $3 (Just $5) $6 $1 ($1 # $2 # $>) }
1236+
| many(outer_attribute) let top_pat initializer ';' { Local $3 Nothing $4 $1 ($1 # $2 # $>) }
12291237
| many(outer_attribute) nonblock_expr ';' { toStmt ($1 `addAttrs` $2) True False ($1 # $2 # $3) }
12301238
| many(outer_attribute) block_like_expr ';' { toStmt ($1 `addAttrs` $2) True True ($1 # $2 # $3) }
12311239
| many(outer_attribute) blockpostfix_expr ';' { toStmt ($1 `addAttrs` $2) True True ($1 # $2 # $3) }

src/Language/Rust/Pretty/Internal.hs

+8-10
Original file line numberDiff line numberDiff line change
@@ -375,9 +375,9 @@ printExprOuterAttrStyle expr isInline = glue (printEitherAttrs (expressionAttrs
375375
in annotate x (hsep [ f e, "as", printType ty ])
376376
TypeAscription _ e ty x -> annotate x (printExpr e <> ":" <+> printType ty)
377377
If _ test blk els x -> annotate x (hsep [ "if", printExpr test, printBlock blk, printElse els ])
378-
IfLet _ pats e blk els x -> annotate x (hsep [ "if let", printPats pats, "=", printExpr e, printBlock blk, printElse els ])
378+
IfLet _ pats e blk els x -> annotate x (hsep [ "if let", printPat pats, "=", printExpr e, printBlock blk, printElse els ])
379379
While as test blk lbl x -> annotate x (hsep [ printLbl lbl, "while", printExpr test, printBlockWithAttrs True blk as ])
380-
WhileLet as ps e blk lbl x -> annotate x (hsep [ printLbl lbl, "while let", printPats ps, "=", printExpr e, printBlockWithAttrs True blk as ])
380+
WhileLet as ps e blk lbl x -> annotate x (hsep [ printLbl lbl, "while let", printPat ps, "=", printExpr e, printBlockWithAttrs True blk as ])
381381
ForLoop as pat e blk lbl x -> annotate x (hsep [ printLbl lbl, "for", printPat pat, "in", printExpr e, printBlockWithAttrs True blk as ])
382382
Loop as blk lbl x -> annotate x (hsep [ printLbl lbl, "loop", printBlockWithAttrs True blk as ])
383383
Match as e arms x -> annotate x (hsep [ "match", printExpr e, block Brace False "," (printInnerAttrs as) (printArm `map` arms) ])
@@ -515,15 +515,12 @@ printFnBlockArgs (FnDecl args ret _ x) = annotate x ("|" <> args' <> "|" <+> ret
515515

516516
-- | Print the arm of a match expression (@print_arm@)
517517
printArm :: Arm a -> Doc a
518-
printArm (Arm as pats guard body x) = annotate x $ printOuterAttrs as
519-
</> printPats pats
518+
printArm (Arm as pat guard body x) = annotate x $ printOuterAttrs as
519+
</> printPat pat
520520
<+> perhaps (\e -> "if" <+> printExpr e) guard
521521
<+> "=>"
522522
<+> printExpr body
523523

524-
printPats :: Foldable f => f (Pat a) -> Doc a
525-
printPats pats = group (foldr1 (\a b -> a <+> "|" <#> b) (printPat `map` toList pats))
526-
527524
-- | Print a block
528525
printBlock :: Block a -> Doc a
529526
printBlock blk = printBlockWithAttrs True blk []
@@ -536,7 +533,7 @@ printBlockWithAttrs b (Block stmts rules x) as = annotate x (printUnsafety rules
536533
| otherwise = body ++ [ lastStmt ]
537534

538535
body = printStmt `map` Prelude.init stmts
539-
536+
540537
lastStmt = case last stmts of
541538
NoSemi expr _ -> printExprOuterAttrStyle expr False
542539
stmt -> printStmt stmt
@@ -545,11 +542,11 @@ printBlockWithAttrs b (Block stmts rules x) as = annotate x (printUnsafety rules
545542
printElse :: Maybe (Expr a) -> Doc a
546543
printElse Nothing = mempty
547544
printElse (Just (If _ e t s x)) = annotate x (hsep [ "else if", printExpr e, printBlock t, printElse s ])
548-
printElse (Just (IfLet _ p e t s x)) = annotate x (hsep [ "else if let", printPats p, "=", printExpr e, printBlock t, printElse s ])
545+
printElse (Just (IfLet _ p e t s x)) = annotate x (hsep [ "else if let", printPat p, "=", printExpr e, printBlock t, printElse s ])
549546
printElse (Just (BlockExpr _ blk x)) = annotate x (hsep [ "else", printBlock blk ])
550547
printElse _ = error "printElse saw `if` with a weird alternative"
551548

552-
-- | Print a binary operator
549+
-- | Print a binary operator
553550
printBinOp :: BinOp -> Doc a
554551
printBinOp AddOp = "+"
555552
printBinOp SubOp = "-"
@@ -878,6 +875,7 @@ printPat (PathP (Just qself) path x) = annotate x (printQPath path qself True
878875
printPat (TupleP [RestP y] x) = annotate x ("(" <> annotate y ".." <> ")")
879876
printPat (TupleP [elt] x) = annotate x ("(" <> printPat elt <> ",)")
880877
printPat (TupleP elts x) = annotate x ("(" <> commas elts printPat <> ")")
878+
printPat (OrP ps x) = annotate x (group (foldr1 (\a b -> a <+> "|" <#> b) (printPat `map` toList ps)))
881879
printPat (BoxP inner x) = annotate x ("box" <+> printPat inner)
882880
printPat (RefP inner mutbl x) = annotate x ("&" <> printMutability mutbl <+> printPat inner)
883881
printPat (LitP expr x) = annotate x (printExpr expr)

src/Language/Rust/Pretty/Resolve.hs

+10-5
Original file line numberDiff line numberDiff line change
@@ -575,6 +575,7 @@ instance (Typeable a, Monoid a) => Resolve (LifetimeDef a) where resolveM = reso
575575
--------------
576576
-- TODO: consider disallowind `..` not in the allowed contexts
577577
-- TODO: use parenP
578+
-- TODO: handling of Or patterns. They are not allowed everywhere!
578579

579580
-- | A pattern can be invalid of
580581
--
@@ -601,6 +602,10 @@ resolvePat p@(PathP q@(Just (QSelf _ i)) p'@(Path g s x) x')
601602
resolvePat p@(TupleP ps x) = scope p $ do
602603
ps' <- traverse resolvePat ps
603604
pure (TupleP ps' x)
605+
-- OrP
606+
resolvePat p@(OrP ps x) = scope p $ do
607+
ps' <- traverse resolvePat ps
608+
pure (OrP ps' x)
604609

605610
-- Everything else...
606611
resolvePat p@(LitP e x) = scope p (LitP <$> resolveExpr LitExpr e <*> pure x)
@@ -990,7 +995,7 @@ resolveExprP p c i@(If as e b es x) = scope i $ do
990995
pure (If as' e' b' es' x)
991996
resolveExprP p c i@(IfLet as p' e b es x) = scope i $ do
992997
as' <- traverse (resolveAttr OuterAttr) as
993-
p'' <- traverse resolvePat p'
998+
p'' <- resolvePat p'
994999
e' <- resolveExprP 0 NoStructExpr e
9951000
b' <- resolveBlock b
9961001
es' <- case es of
@@ -1008,7 +1013,7 @@ resolveExprP _ _ w@(While as e b l x) = scope w $ do
10081013
pure (While as' e' b' l' x)
10091014
resolveExprP _ _ w@(WhileLet as p' e b l x) = scope w $ do
10101015
as' <- traverse (resolveAttr EitherAttr) as
1011-
p'' <- traverse resolvePat p'
1016+
p'' <- resolvePat p'
10121017
e' <- resolveExprP 0 NoStructExpr e
10131018
b' <- resolveBlock b
10141019
l' <- traverse resolveLbl l
@@ -1069,12 +1074,12 @@ instance (Typeable a, Monoid a) => Resolve (Field a) where resolveM = resolveFie
10691074

10701075
-- | Arms are invalid only if the underlying consitutents are
10711076
resolveArm :: (Typeable a, Monoid a) => Arm a -> ResolveM (Arm a)
1072-
resolveArm a@(Arm as ps g b x) = scope a $ do
1077+
resolveArm a@(Arm as p g b x) = scope a $ do
10731078
as' <- traverse (resolveAttr OuterAttr) as
1074-
ps' <- traverse resolvePat ps
1079+
p' <- resolvePat p
10751080
g' <- traverse (resolveExpr AnyExpr) g
10761081
b' <- resolveExpr SemiExpr b
1077-
pure (Arm as' ps' g' b' x)
1082+
pure (Arm as' p' g' b' x)
10781083

10791084
instance (Typeable a, Monoid a) => Resolve (Arm a) where resolveM = resolveArm
10801085

src/Language/Rust/Syntax/AST.hs

+8-5
Original file line numberDiff line numberDiff line change
@@ -169,8 +169,8 @@ data Abi
169169
-- }
170170
-- @
171171
data Arg a
172-
= Arg (Maybe (Pat a)) (Ty a) a -- ^ Regular argument
173-
| SelfValue Mutability a -- ^ Self argument, by value
172+
= Arg (Maybe (Pat a)) (Ty a) a -- ^ Regular argument
173+
| SelfValue Mutability a -- ^ Self argument, by value
174174
| SelfRegion (Maybe (Lifetime a)) Mutability a -- ^ Self argument, by reference
175175
| SelfExplicit (Ty a) Mutability a -- ^ Explicit self argument
176176
deriving (Eq, Ord, Show, Functor, Typeable, Data, Generic, Generic1, NFData)
@@ -193,7 +193,7 @@ instance Located a => Located (Arg a) where
193193
-- _ => println!("{} % 2 = 0", n)
194194
-- }
195195
-- @
196-
data Arm a = Arm [Attribute a] (NonEmpty (Pat a)) (Maybe (Expr a)) (Expr a) a
196+
data Arm a = Arm [Attribute a] (Pat a) (Maybe (Expr a)) (Expr a) a
197197
deriving (Eq, Ord, Show, Functor, Typeable, Data, Generic, Generic1, NFData)
198198

199199
instance Located a => Located (Arm a) where spanOf (Arm _ _ _ _ s) = spanOf s
@@ -316,11 +316,11 @@ data Expr a
316316
-- type of the @if@ is inferred to be @()@. (example: @if 1 == 2 { (1,1) } else { (2,2) }@
317317
| If [Attribute a] (Expr a) (Block a) (Maybe (Expr a)) a
318318
-- | if-let expression with an optional else block (example: @if let Some(x) = None { () }@)
319-
| IfLet [Attribute a] (NonEmpty (Pat a)) (Expr a) (Block a) (Maybe (Expr a)) a
319+
| IfLet [Attribute a] (Pat a) (Expr a) (Block a) (Maybe (Expr a)) a
320320
-- | while loop, with an optional label (example: @'lbl: while 1 == 1 { break 'lbl }@)
321321
| While [Attribute a] (Expr a) (Block a) (Maybe (Label a)) a
322322
-- | while-let loop, with an optional label (example: @while let Some(x) = None { x }@)
323-
| WhileLet [Attribute a] (NonEmpty (Pat a)) (Expr a) (Block a) (Maybe (Label a)) a
323+
| WhileLet [Attribute a] (Pat a) (Expr a) (Block a) (Maybe (Label a)) a
324324
-- | for loop, with an optional label (example: @for i in 1..10 { println!("{}",i) }@)
325325
| ForLoop [Attribute a] (Pat a) (Expr a) (Block a) (Maybe (Label a)) a
326326
-- | conditionless loop (can be exited with 'Break', 'Continue', or 'Ret')
@@ -783,6 +783,8 @@ data Pat a
783783
| PathP (Maybe (QSelf a)) (Path a) a
784784
-- | tuple pattern (example: @(a, b)@)
785785
| TupleP [Pat a] a
786+
-- | or pattern, must have more than one variant (example: @Some(0) | None@)
787+
| OrP (NonEmpty (Pat a)) a
786788
-- | box pattern (example: @box _@)
787789
| BoxP (Pat a) a
788790
-- | reference pattern (example: @&mut (a, b)@)
@@ -809,6 +811,7 @@ instance Located a => Located (Pat a) where
809811
spanOf (TupleStructP _ _ s) = spanOf s
810812
spanOf (PathP _ _ s) = spanOf s
811813
spanOf (TupleP _ s) = spanOf s
814+
spanOf (OrP _ s) = spanOf s
812815
spanOf (BoxP _ s) = spanOf s
813816
spanOf (RefP _ _ s) = spanOf s
814817
spanOf (LitP _ s) = spanOf s

0 commit comments

Comments
 (0)