use crate::ast::prelude::*;
#[test]
#[cfg(not(miri))]
fn ast_parse() {
rt::<ast::Pat>("()");
rt::<ast::Pat>("42");
rt::<ast::Pat>("-42");
rt::<ast::Pat>("3.1415");
rt::<ast::Pat>("-3.1415");
rt::<ast::Pat>("b'a'");
rt::<ast::Pat>("'a'");
rt::<ast::Pat>("b\"hello world\"");
rt::<ast::Pat>("\"hello world\"");
rt::<ast::Pat>("var");
rt::<ast::Pat>("_");
rt::<ast::Pat>("Foo(n)");
}
#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)]
#[non_exhaustive]
pub enum Pat {
Ignore(PatIgnore),
Path(PatPath),
Lit(PatLit),
Vec(PatVec),
Tuple(PatTuple),
Object(PatObject),
Binding(PatBinding),
Rest(PatRest),
}
impl Parse for Pat {
fn parse(p: &mut Parser<'_>) -> Result<Self> {
let attributes = p.parse::<Vec<ast::Attribute>>()?;
match p.nth(0)? {
K![byte] => {
return Ok(Self::Lit(PatLit {
attributes,
expr: Box::try_new(ast::Expr::from_lit(ast::Lit::Byte(p.parse()?)))?,
}));
}
K![char] => {
return Ok(Self::Lit(PatLit {
attributes,
expr: Box::try_new(ast::Expr::from_lit(ast::Lit::Char(p.parse()?)))?,
}));
}
K![bytestr] => {
return Ok(Self::Lit(PatLit {
attributes,
expr: Box::try_new(ast::Expr::from_lit(ast::Lit::ByteStr(p.parse()?)))?,
}));
}
K![true] | K![false] => {
return Ok(Self::Lit(PatLit {
attributes,
expr: Box::try_new(ast::Expr::from_lit(ast::Lit::Bool(p.parse()?)))?,
}));
}
K![str] => {
return Ok(match p.nth(1)? {
K![:] => Self::Binding(PatBinding {
attributes,
key: ast::ObjectKey::LitStr(p.parse()?),
colon: p.parse()?,
pat: p.parse()?,
}),
_ => Self::Lit(PatLit {
attributes,
expr: Box::try_new(ast::Expr::from_lit(ast::Lit::Str(p.parse()?)))?,
}),
});
}
K![number] => {
return Ok(Self::Lit(PatLit {
attributes,
expr: Box::try_new(ast::Expr::from_lit(ast::Lit::Number(p.parse()?)))?,
}));
}
K![..] => {
return Ok(Self::Rest(PatRest {
attributes,
dot_dot: p.parse()?,
}))
}
K!['('] => {
return Ok({
let _nth = p.nth(1)?;
Self::Tuple(PatTuple {
attributes,
path: None,
items: p.parse()?,
})
});
}
K!['['] => {
return Ok(Self::Vec(PatVec {
attributes,
items: p.parse()?,
}))
}
K![#] => {
return Ok(Self::Object(PatObject {
attributes,
ident: p.parse()?,
items: p.parse()?,
}))
}
K![-] => {
let expr: ast::Expr = p.parse()?;
if expr.is_lit() {
return Ok(Self::Lit(PatLit {
attributes,
expr: Box::try_new(expr)?,
}));
}
}
K![_] => {
return Ok(Self::Ignore(PatIgnore {
attributes,
underscore: p.parse()?,
}))
}
_ if ast::Path::peek(p.peeker()) => {
let path = p.parse::<ast::Path>()?;
return Ok(match p.nth(0)? {
K!['('] => Self::Tuple(PatTuple {
attributes,
path: Some(path),
items: p.parse()?,
}),
K!['{'] => Self::Object(PatObject {
attributes,
ident: ast::ObjectIdent::Named(path),
items: p.parse()?,
}),
K![:] => Self::Binding(PatBinding {
attributes,
key: ast::ObjectKey::Path(path),
colon: p.parse()?,
pat: p.parse()?,
}),
_ => Self::Path(PatPath { attributes, path }),
});
}
_ => (),
}
Err(compile::Error::expected(p.tok_at(0)?, "pattern"))
}
}
impl Peek for Pat {
fn peek(p: &mut Peeker<'_>) -> bool {
match p.nth(0) {
K!['('] => true,
K!['['] => true,
K![#] => matches!(p.nth(1), K!['{']),
K![_] => true,
K![..] => true,
K![byte] | K![char] | K![number] | K![str] => true,
K![true] | K![false] => true,
K![-] => matches!(p.nth(1), K![number]),
_ => ast::Path::peek(p),
}
}
}
#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)]
#[non_exhaustive]
pub struct PatLit {
#[rune(iter)]
pub attributes: Vec<ast::Attribute>,
pub expr: Box<ast::Expr>,
}
#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)]
#[non_exhaustive]
pub struct PatRest {
#[rune(iter)]
pub attributes: Vec<ast::Attribute>,
pub dot_dot: T![..],
}
#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)]
#[non_exhaustive]
pub struct PatVec {
#[rune(iter)]
pub attributes: Vec<ast::Attribute>,
pub items: ast::Bracketed<ast::Pat, T![,]>,
}
#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)]
#[non_exhaustive]
pub struct PatTuple {
#[rune(iter)]
pub attributes: Vec<ast::Attribute>,
#[rune(iter)]
pub path: Option<ast::Path>,
pub items: ast::Parenthesized<ast::Pat, T![,]>,
}
#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)]
#[non_exhaustive]
pub struct PatObject {
#[rune(iter)]
pub attributes: Vec<ast::Attribute>,
pub ident: ast::ObjectIdent,
pub items: ast::Braced<Pat, T![,]>,
}
#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned, Parse)]
#[non_exhaustive]
pub struct PatBinding {
#[rune(iter)]
pub attributes: Vec<ast::Attribute>,
pub key: ast::ObjectKey,
pub colon: T![:],
pub pat: Box<ast::Pat>,
}
#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)]
#[non_exhaustive]
pub struct PatPath {
#[rune(iter)]
pub attributes: Vec<ast::Attribute>,
pub path: ast::Path,
}
#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)]
#[non_exhaustive]
pub struct PatIgnore {
#[rune(iter)]
pub attributes: Vec<ast::Attribute>,
pub underscore: T![_],
}