rustidy_ast/expr/with_block/
match_.rs1use {
5 crate::{
6 attr::{self, BracedWithInnerAttributes, WithOuterAttributes},
7 expr::{Expression, ExpressionInner, ExpressionWithBlock, ExpressionWithoutBlock},
8 pat::Pattern,
9 token,
10 },
11 super::Conditions,
12 core::ops::ControlFlow,
13 rustidy_format::{Format, Formattable, WhitespaceFormat},
14 rustidy_parse::{FromRecursiveRoot, Parse, ParseError, Parser, ParserError, ParserTag},
15 rustidy_print::Print,
16 rustidy_util::Whitespace,
17};
18
19#[derive(PartialEq, Eq, Clone, Debug)]
21#[derive(serde::Serialize, serde::Deserialize)]
22#[derive(Parse, Formattable, Format, Print)]
23#[parse(name = "a match expression")]
24pub struct MatchExpression {
25 pub match_: token::Match,
26 #[parse(fatal)]
27 #[format(prefix_ws = Whitespace::SINGLE)]
28 pub scrutinee: Box<Scrutinee>,
29 #[format(prefix_ws = Whitespace::SINGLE)]
30 pub arms: BracedWithInnerAttributes<Option<MatchArms>>,
31}
32
33#[derive(PartialEq, Eq, Clone, Debug)]
35#[derive(serde::Serialize, serde::Deserialize)]
36#[derive(Parse, Formattable, Format, Print)]
37pub struct Scrutinee(#[parse(with_tag = ParserTag::SkipStructExpression)] Expression);
38
39#[derive(PartialEq, Eq, Clone, Debug)]
41#[derive(serde::Serialize, serde::Deserialize)]
42#[derive(Formattable, Format, Print)]
43pub struct MatchArms {
44 #[format(args = rustidy_format::vec::args_prefix_ws(Whitespace::INDENT))]
45 pub arms: Vec<MatchArmWithExpr>,
46}
47
48impl Parse for MatchArms {
49 type Error = MatchArmsError;
50
51 fn parse_from(parser: &mut Parser) -> Result<Self, Self::Error> {
52 let mut arms = vec![];
53 loop {
54 let arm_res = parser.try_parse::<MatchArm>()?;
57 let Ok(arm) = arm_res else {
58 break
59 };
60 let arrow = parser.parse::<token::FatArrow>()?;
61
62
63 let with_block_res = parser
67 .peek::<(ExpressionWithBlock, Option<token::Comma>)>()?;
68 let without_block_res = parser
69 .peek::<(ExpressionWithoutBlock, Option<token::Comma>)>()?;
70 let (expr, trailing_comma, control_flow) = match (with_block_res, without_block_res) {
71 (Ok(((expr_with_block, with_block_trailing_comma), with_block_peek_state)), Ok(((expr_without_block, without_block_trailing_comma), without_block_peek_state)),) => match without_block_trailing_comma {
73 Some(trailing_comma) => {
74 parser.set_peeked(without_block_peek_state);
75
76 let expr = Expression::from_recursive_root(
77 ExpressionInner::from(expr_without_block),
78 parser
79 );
80 (expr, Some(trailing_comma), ControlFlow::Continue(()))
81 },
82 None => {
83 parser.set_peeked(with_block_peek_state);
84
85 let expr = Expression::from_recursive_root(ExpressionInner::from(expr_with_block), parser);
86 (expr, with_block_trailing_comma, ControlFlow::Continue(()))
87 },
88 },
89 (Ok(((expr, trailing_comma), peek_state)), Err(_)) => {
91 parser.set_peeked(peek_state);
92
93 let expr = Expression::from_recursive_root(ExpressionInner::from(expr), parser);
94 (expr, trailing_comma, ControlFlow::Continue(()))
95 },
96 (Err(_), Ok(((expr, trailing_comma), peek_state))) => {
97 parser.set_peeked(peek_state);
98
99 let expr = Expression::from_recursive_root(ExpressionInner::from(expr), parser);
100 let control_flow = match trailing_comma.is_some() {
101 true => ControlFlow::Continue(()),
102 false => ControlFlow::Break(()),
103 };
104
105 (expr, trailing_comma, control_flow)
106 },
107 (Err(with_block), Err(without_block)) => return Err(
108 Self::Error::Expression { with_block, without_block, }
109 ),
110 };
111
112 arms.push(
113 MatchArmWithExpr { arm, arrow, expr, trailing_comma, }
114 );
115
116 if control_flow.is_break() {
117 break;
118 }
119 }
120
121 Ok(Self { arms })
122 }
123}
124
125#[derive(derive_more::Debug, derive_more::From, ParseError)]
126pub enum MatchArmsError {
127 #[parse_error(transparent)]
128 MatchArm(ParserError<MatchArm>),
129
130 #[parse_error(transparent)]
131 #[parse_error(fatal)]
132 FatArrow(ParserError<token::FatArrow>),
133
134 #[parse_error(transparent)]
135 #[parse_error(fatal)]
136 ExpressionWithBlock(ParserError<(ExpressionWithBlock, Option<token::Comma>)>),
137
138 #[parse_error(transparent)]
139 #[parse_error(fatal)]
140 ExpressionWithoutBlock(ParserError<(ExpressionWithoutBlock, Option<token::Comma>)>),
141
142 #[parse_error(multiple)]
143 #[parse_error(fatal)]
144 Expression {
145 with_block: ParserError<(ExpressionWithBlock, Option<token::Comma>)>,
146 without_block: ParserError<(ExpressionWithoutBlock, Option<token::Comma>)>,
147 },
148
149 #[parse_error(transparent)]
150 #[parse_error(fatal)]
151 Comma(ParserError<token::Comma>),
152}
153
154#[derive(PartialEq, Eq, Clone, Debug)]
155#[derive(serde::Serialize, serde::Deserialize)]
156#[derive(Parse, Formattable, Format, Print)]
157pub struct MatchArmWithExpr {
158 pub arm: MatchArm,
159 #[format(prefix_ws = Whitespace::SINGLE)]
160 pub arrow: token::FatArrow,
161 #[format(prefix_ws = Whitespace::SINGLE)]
162 pub expr: Expression,
163 #[format(prefix_ws = Whitespace::REMOVE)]
164 pub trailing_comma: Option<token::Comma>,
165}
166
167#[derive(PartialEq, Eq, Clone, Debug)]
169#[derive(serde::Serialize, serde::Deserialize)]
170#[derive(Parse, Formattable, Format, Print)]
171pub struct MatchArm(
172 #[format(args = attr::with::fmt(Whitespace::INDENT))]
173 pub WithOuterAttributes<MatchArmInner>,
174);
175
176#[derive(PartialEq, Eq, Clone, Debug)]
177#[derive(serde::Serialize, serde::Deserialize)]
178#[derive(Parse, Formattable, Format, Print)]
179#[parse(name = "a match arm")]
180pub struct MatchArmInner {
181 pub pat: Pattern,
182 #[format(prefix_ws = Whitespace::SINGLE)]
183 pub guard: Option<MatchArmGuard>,
184}
185
186#[derive(PartialEq, Eq, Clone, Debug)]
188#[derive(serde::Serialize, serde::Deserialize)]
189#[derive(Parse, Formattable, Format, Print)]
190pub struct MatchArmGuard {
191 pub if_: token::If,
192 #[format(prefix_ws = Whitespace::SINGLE)]
196 pub cond: Conditions,
197}