Skip to main content

rune/ast/
pat.rs

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/// A pattern match.
21#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)]
22#[non_exhaustive]
23pub enum Pat {
24    /// An ignored binding `_`.
25    Ignore(PatIgnore),
26    /// A variable binding `n`.
27    Path(PatPath),
28    /// A literal pattern. This is represented as an expression.
29    Lit(PatLit),
30    /// A vector pattern.
31    Vec(PatVec),
32    /// A tuple pattern.
33    Tuple(PatTuple),
34    /// An object pattern.
35    Object(PatObject),
36    /// A binding `a: pattern` or `"foo": pattern`.
37    Binding(PatBinding),
38    /// The rest pattern `..`.
39    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    /// Patterns nest independently of expressions, so how deeply they nest is
50    /// bounded here as well as in [`ast::Expr`].
51    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/// A literal pattern.
192#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)]
193#[non_exhaustive]
194pub struct PatLit {
195    /// Attributes associated with the pattern.
196    #[rune(iter)]
197    pub attributes: Vec<ast::Attribute>,
198    /// The literal expression.
199    pub expr: Box<ast::Expr>,
200}
201
202/// The rest pattern `..` and associated attributes.
203#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)]
204#[non_exhaustive]
205pub struct PatRest {
206    /// Attribute associated with the rest pattern.
207    #[rune(iter)]
208    pub attributes: Vec<ast::Attribute>,
209    /// The rest token `..`.
210    pub dot_dot: T![..],
211}
212
213/// An array pattern.
214#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)]
215#[non_exhaustive]
216pub struct PatVec {
217    /// Attributes associated with the vector pattern.
218    #[rune(iter)]
219    pub attributes: Vec<ast::Attribute>,
220    /// Bracketed patterns.
221    pub items: ast::Bracketed<ast::Pat, T![,]>,
222}
223
224/// A tuple pattern.
225#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)]
226#[non_exhaustive]
227pub struct PatTuple {
228    /// Attributes associated with the object pattern.
229    #[rune(iter)]
230    pub attributes: Vec<ast::Attribute>,
231    /// The path, if the tuple is typed.
232    #[rune(iter)]
233    pub path: Option<ast::Path>,
234    /// The items in the tuple.
235    pub items: ast::Parenthesized<ast::Pat, T![,]>,
236}
237
238/// An object pattern.
239#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)]
240#[non_exhaustive]
241pub struct PatObject {
242    /// Attributes associated with the object pattern.
243    #[rune(iter)]
244    pub attributes: Vec<ast::Attribute>,
245    /// The identifier of the object pattern.
246    pub ident: ast::ObjectIdent,
247    /// The fields matched against.
248    pub items: ast::Braced<Pat, T![,]>,
249}
250
251/// An object item.
252#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned, Parse)]
253#[non_exhaustive]
254pub struct PatBinding {
255    /// Attributes associate with the binding.
256    #[rune(iter)]
257    pub attributes: Vec<ast::Attribute>,
258    /// The key of an object.
259    pub key: ast::ObjectKey,
260    /// The colon separator for the binding.
261    pub colon: T![:],
262    /// What the binding is to.
263    pub pat: Box<ast::Pat>,
264}
265
266/// A path pattern.
267#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)]
268#[non_exhaustive]
269pub struct PatPath {
270    /// Attributes associate with the path.
271    #[rune(iter)]
272    pub attributes: Vec<ast::Attribute>,
273    /// The path of the pattern.
274    pub path: ast::Path,
275}
276
277/// An ignore pattern.
278#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)]
279#[non_exhaustive]
280pub struct PatIgnore {
281    /// Attributes associate with the pattern.
282    #[rune(iter)]
283    pub attributes: Vec<ast::Attribute>,
284    /// The ignore token`_`.
285    pub underscore: T![_],
286}