rune/ast/
expr_unary.rs

1use core::fmt;
2
3use crate::ast::prelude::*;
4
5#[test]
6#[cfg(not(miri))]
7fn ast_parse() {
8    rt::<ast::ExprUnary>("!0");
9    rt::<ast::ExprUnary>("*foo");
10    rt::<ast::ExprUnary>("&foo");
11    rt::<ast::ExprUnary>(
12        "&Foo {
13        a: 42,
14    }",
15    );
16
17    rt::<ast::UnOp>("!");
18    rt::<ast::UnOp>("-");
19    rt::<ast::UnOp>("&");
20    rt::<ast::UnOp>("*");
21}
22
23/// A unary expression.
24#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)]
25#[non_exhaustive]
26pub struct ExprUnary {
27    /// Attributes associated with expression.
28    #[rune(iter)]
29    pub attributes: Vec<ast::Attribute>,
30    /// The operation to apply.
31    pub op: UnOp,
32    /// The expression of the operation.
33    pub expr: Box<ast::Expr>,
34}
35
36impl ExprUnary {
37    /// Parse the uniary expression with the given meta and configuration.
38    pub(crate) fn parse_with_meta(
39        p: &mut Parser,
40        attributes: Vec<ast::Attribute>,
41        eager_brace: ast::expr::EagerBrace,
42    ) -> Result<Self> {
43        Ok(Self {
44            attributes,
45            op: p.parse()?,
46            expr: Box::try_new(ast::Expr::parse_with(
47                p,
48                eager_brace,
49                ast::expr::NOT_EAGER_BINARY,
50                ast::expr::CALLABLE,
51            )?)?,
52        })
53    }
54}
55
56expr_parse!(Unary, ExprUnary, "try expression");
57
58/// A unary operation.
59#[derive(Debug, TryClone, Clone, Copy, PartialEq, Eq, ToTokens, Spanned)]
60#[try_clone(copy)]
61pub enum UnOp {
62    /// Not `!<thing>`.
63    Not(ast::Bang),
64    /// Negation `-<thing>`.
65    Neg(ast::Dash),
66    /// Reference `&<thing>`.
67    BorrowRef(ast::Amp),
68    /// Dereference `*<thing>`.
69    Deref(ast::Star),
70}
71
72impl ToAst for UnOp {
73    fn to_ast(span: Span, kind: ast::Kind) -> compile::Result<Self> {
74        match kind {
75            K![!] => Ok(Self::Not(ast::Bang { span })),
76            K![-] => Ok(Self::Neg(ast::Dash { span })),
77            K![&] => Ok(Self::BorrowRef(ast::Amp { span })),
78            K![*] => Ok(Self::Deref(ast::Star { span })),
79            _ => Err(compile::Error::expected(
80                ast::Token { span, kind },
81                "unary operator, like `!` or `-`",
82            )),
83        }
84    }
85
86    #[inline]
87    fn matches(kind: &ast::Kind) -> bool {
88        matches!(kind, K![!] | K![-] | K![&] | K![*])
89    }
90
91    #[inline]
92    fn into_expectation() -> Expectation {
93        Expectation::Description("a unary operation")
94    }
95}
96
97impl Parse for UnOp {
98    fn parse(p: &mut Parser<'_>) -> Result<Self> {
99        let token = p.next()?;
100        Self::to_ast(token.span, token.kind)
101    }
102}
103
104impl fmt::Display for UnOp {
105    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
106        match self {
107            Self::Not(..) => write!(f, "!")?,
108            Self::Neg(..) => write!(f, "-")?,
109            Self::BorrowRef(..) => write!(f, "&")?,
110            Self::Deref(..) => write!(f, "*")?,
111        }
112
113        Ok(())
114    }
115}