use crate::ast;
use crate::{Parse, ParseError, Parser, Peek, Peeker, Spanned, ToTokens};
#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Spanned)]
pub enum Pat {
PatIgnore(PatIgnore),
PatPath(PatPath),
PatLit(PatLit),
PatVec(PatVec),
PatTuple(PatTuple),
PatObject(PatObject),
PatBinding(PatBinding),
PatRest(PatRest),
}
impl Parse for Pat {
fn parse(p: &mut Parser<'_>) -> Result<Self, ParseError> {
let attributes = p.parse::<Vec<ast::Attribute>>()?;
match p.nth(0)? {
K![byte] => {
return Ok(Self::PatLit(PatLit {
attributes,
expr: ast::Expr::from_lit(ast::Lit::Byte(p.parse()?)),
}));
}
K![char] => {
return Ok(Self::PatLit(PatLit {
attributes,
expr: ast::Expr::from_lit(ast::Lit::Char(p.parse()?)),
}));
}
K![bytestr] => {
return Ok(Self::PatLit(PatLit {
attributes,
expr: ast::Expr::from_lit(ast::Lit::ByteStr(p.parse()?)),
}));
}
K![true] | K![false] => {
return Ok(Self::PatLit(PatLit {
attributes,
expr: ast::Expr::from_lit(ast::Lit::Bool(p.parse()?)),
}));
}
K![str] => {
return Ok(match p.nth(1)? {
K![:] => Self::PatBinding(PatBinding {
attributes,
key: ast::ObjectKey::LitStr(p.parse()?),
colon: p.parse()?,
pat: p.parse()?,
}),
_ => Self::PatLit(PatLit {
attributes,
expr: ast::Expr::from_lit(ast::Lit::Str(p.parse()?)),
}),
});
}
K![number] => {
return Ok(Self::PatLit(PatLit {
attributes,
expr: ast::Expr::from_lit(ast::Lit::Number(p.parse()?)),
}));
}
K![..] => {
return Ok(Self::PatRest(PatRest {
attributes,
dot_dot: p.parse()?,
}))
}
K!['('] => {
return Ok(match p.nth(1)? {
_ => Self::PatTuple(PatTuple {
attributes,
path: None,
items: p.parse()?,
}),
});
}
K!['['] => {
return Ok(Self::PatVec(PatVec {
attributes,
items: p.parse()?,
}))
}
K![#] => {
return Ok(Self::PatObject(PatObject {
attributes,
ident: p.parse()?,
items: p.parse()?,
}))
}
K![-] => {
let expr: ast::Expr = p.parse()?;
if expr.is_lit() {
return Ok(Self::PatLit(PatLit { attributes, expr }));
}
}
K![_] => {
return Ok(Self::PatIgnore(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::PatTuple(PatTuple {
attributes,
path: Some(path),
items: p.parse()?,
}),
K!['{'] => Self::PatObject(PatObject {
attributes,
ident: ast::ObjectIdent::Named(path),
items: p.parse()?,
}),
K![:] => Self::PatBinding(PatBinding {
attributes,
key: ast::ObjectKey::Path(path),
colon: p.parse()?,
pat: p.parse()?,
}),
_ => Self::PatPath(PatPath { attributes, path }),
});
}
_ => (),
}
Err(ParseError::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, Clone, PartialEq, Eq, ToTokens, Spanned)]
pub struct PatLit {
#[rune(iter)]
pub attributes: Vec<ast::Attribute>,
pub expr: ast::Expr,
}
#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Spanned)]
pub struct PatRest {
#[rune(iter)]
pub attributes: Vec<ast::Attribute>,
pub dot_dot: T![..],
}
#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Spanned)]
pub struct PatVec {
#[rune(iter)]
pub attributes: Vec<ast::Attribute>,
pub items: ast::Bracketed<ast::Pat, T![,]>,
}
#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Spanned)]
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, Clone, PartialEq, Eq, ToTokens, Spanned)]
pub struct PatObject {
#[rune(iter)]
pub attributes: Vec<ast::Attribute>,
pub ident: ast::ObjectIdent,
pub items: ast::Braced<Pat, T![,]>,
}
#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Spanned, Parse)]
pub struct PatBinding {
#[rune(iter)]
pub attributes: Vec<ast::Attribute>,
pub key: ast::ObjectKey,
pub colon: T![:],
pub pat: Box<ast::Pat>,
}
#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Spanned)]
pub struct PatPath {
#[rune(iter)]
pub attributes: Vec<ast::Attribute>,
pub path: ast::Path,
}
#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Spanned)]
pub struct PatIgnore {
#[rune(iter)]
pub attributes: Vec<ast::Attribute>,
pub underscore: T![_],
}