1use crate::ast::prelude::*;
2
3#[test]
4#[cfg(not(miri))]
5fn ast_parse() {
6 rt::<ast::Pat>("()");
7 rt::<ast::Pat>("42");
8 rt::<ast::Pat>("-42");
9 rt::<ast::Pat>("3.1415");
10 rt::<ast::Pat>("-3.1415");
11 rt::<ast::Pat>("b'a'");
12 rt::<ast::Pat>("'a'");
13 rt::<ast::Pat>("b\"hello world\"");
14 rt::<ast::Pat>("\"hello world\"");
15 rt::<ast::Pat>("var");
16 rt::<ast::Pat>("_");
17 rt::<ast::Pat>("Foo(n)");
18}
19
20#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)]
22#[non_exhaustive]
23pub enum Pat {
24 Ignore(PatIgnore),
26 Path(PatPath),
28 Lit(PatLit),
30 Vec(PatVec),
32 Tuple(PatTuple),
34 Object(PatObject),
36 Binding(PatBinding),
38 Rest(PatRest),
40}
41
42impl Parse for Pat {
43 fn parse(p: &mut Parser<'_>) -> Result<Self> {
44 p.nested(Self::parse_inner)
45 }
46}
47
48impl Pat {
49 fn parse_inner(p: &mut Parser<'_>) -> Result<Self> {
52 let attributes = p.parse::<Vec<ast::Attribute>>()?;
53
54 match p.nth(0)? {
55 K![byte] => {
56 return Ok(Self::Lit(PatLit {
57 attributes,
58 expr: Box::try_new(ast::Expr::from_lit(ast::Lit::Byte(p.parse()?)))?,
59 }));
60 }
61 K![char] => {
62 return Ok(Self::Lit(PatLit {
63 attributes,
64 expr: Box::try_new(ast::Expr::from_lit(ast::Lit::Char(p.parse()?)))?,
65 }));
66 }
67 K![bytestr] => {
68 return Ok(Self::Lit(PatLit {
69 attributes,
70 expr: Box::try_new(ast::Expr::from_lit(ast::Lit::ByteStr(p.parse()?)))?,
71 }));
72 }
73 K![true] | K![false] => {
74 return Ok(Self::Lit(PatLit {
75 attributes,
76 expr: Box::try_new(ast::Expr::from_lit(ast::Lit::Bool(p.parse()?)))?,
77 }));
78 }
79 K![str] => {
80 return Ok(match p.nth(1)? {
81 K![:] => Self::Binding(PatBinding {
82 attributes,
83 key: ast::ObjectKey::LitStr(p.parse()?),
84 colon: p.parse()?,
85 pat: p.parse()?,
86 }),
87 _ => Self::Lit(PatLit {
88 attributes,
89 expr: Box::try_new(ast::Expr::from_lit(ast::Lit::Str(p.parse()?)))?,
90 }),
91 });
92 }
93 K![number] => {
94 return Ok(Self::Lit(PatLit {
95 attributes,
96 expr: Box::try_new(ast::Expr::from_lit(ast::Lit::Number(p.parse()?)))?,
97 }));
98 }
99 K![..] => {
100 return Ok(Self::Rest(PatRest {
101 attributes,
102 dot_dot: p.parse()?,
103 }))
104 }
105 K!['('] => {
106 return Ok({
107 let _nth = p.nth(1)?;
108
109 Self::Tuple(PatTuple {
110 attributes,
111 path: None,
112 items: p.parse()?,
113 })
114 });
115 }
116 K!['['] => {
117 return Ok(Self::Vec(PatVec {
118 attributes,
119 items: p.parse()?,
120 }))
121 }
122 K![#] => {
123 return Ok(Self::Object(PatObject {
124 attributes,
125 ident: p.parse()?,
126 items: p.parse()?,
127 }))
128 }
129 K![-] => {
130 let expr: ast::Expr = p.parse()?;
131
132 if expr.is_lit() {
133 return Ok(Self::Lit(PatLit {
134 attributes,
135 expr: Box::try_new(expr)?,
136 }));
137 }
138 }
139 K![_] => {
140 return Ok(Self::Ignore(PatIgnore {
141 attributes,
142 underscore: p.parse()?,
143 }))
144 }
145 _ if ast::Path::peek(p.peeker()) => {
146 let path = p.parse::<ast::Path>()?;
147
148 return Ok(match p.nth(0)? {
149 K!['('] => Self::Tuple(PatTuple {
150 attributes,
151 path: Some(path),
152 items: p.parse()?,
153 }),
154 K!['{'] => Self::Object(PatObject {
155 attributes,
156 ident: ast::ObjectIdent::Named(path),
157 items: p.parse()?,
158 }),
159 K![:] => Self::Binding(PatBinding {
160 attributes,
161 key: ast::ObjectKey::Path(path),
162 colon: p.parse()?,
163 pat: p.parse()?,
164 }),
165 _ => Self::Path(PatPath { attributes, path }),
166 });
167 }
168 _ => (),
169 }
170
171 Err(compile::Error::expected(p.tok_at(0)?, "pattern"))
172 }
173}
174
175impl Peek for Pat {
176 fn peek(p: &mut Peeker<'_>) -> bool {
177 match p.nth(0) {
178 K!['('] => true,
179 K!['['] => true,
180 K![#] => matches!(p.nth(1), K!['{']),
181 K![_] => true,
182 K![..] => true,
183 K![byte] | K![char] | K![number] | K![str] => true,
184 K![true] | K![false] => true,
185 K![-] => matches!(p.nth(1), K![number]),
186 _ => ast::Path::peek(p),
187 }
188 }
189}
190
191#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)]
193#[non_exhaustive]
194pub struct PatLit {
195 #[rune(iter)]
197 pub attributes: Vec<ast::Attribute>,
198 pub expr: Box<ast::Expr>,
200}
201
202#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)]
204#[non_exhaustive]
205pub struct PatRest {
206 #[rune(iter)]
208 pub attributes: Vec<ast::Attribute>,
209 pub dot_dot: T![..],
211}
212
213#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)]
215#[non_exhaustive]
216pub struct PatVec {
217 #[rune(iter)]
219 pub attributes: Vec<ast::Attribute>,
220 pub items: ast::Bracketed<ast::Pat, T![,]>,
222}
223
224#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)]
226#[non_exhaustive]
227pub struct PatTuple {
228 #[rune(iter)]
230 pub attributes: Vec<ast::Attribute>,
231 #[rune(iter)]
233 pub path: Option<ast::Path>,
234 pub items: ast::Parenthesized<ast::Pat, T![,]>,
236}
237
238#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)]
240#[non_exhaustive]
241pub struct PatObject {
242 #[rune(iter)]
244 pub attributes: Vec<ast::Attribute>,
245 pub ident: ast::ObjectIdent,
247 pub items: ast::Braced<Pat, T![,]>,
249}
250
251#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned, Parse)]
253#[non_exhaustive]
254pub struct PatBinding {
255 #[rune(iter)]
257 pub attributes: Vec<ast::Attribute>,
258 pub key: ast::ObjectKey,
260 pub colon: T![:],
262 pub pat: Box<ast::Pat>,
264}
265
266#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)]
268#[non_exhaustive]
269pub struct PatPath {
270 #[rune(iter)]
272 pub attributes: Vec<ast::Attribute>,
273 pub path: ast::Path,
275}
276
277#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)]
279#[non_exhaustive]
280pub struct PatIgnore {
281 #[rune(iter)]
283 pub attributes: Vec<ast::Attribute>,
284 pub underscore: T![_],
286}