rune/ast/
ident.rs

1use crate::ast::prelude::*;
2
3#[test]
4#[cfg(not(miri))]
5fn ast_parse() {
6    rt::<ast::Ident>("foo");
7    rt::<ast::Ident>("a42");
8    rt::<ast::Ident>("_ignored");
9}
10
11/// An identifier, like `foo` or `Hello`.
12///
13/// # Constructing identifiers
14///
15/// Inside of a macro context, identifiers have to be constructed through
16/// [MacroContext::ident][crate::macros::MacroContext::ident].
17///
18/// ```
19/// use rune::ast;
20/// use rune::macros;
21///
22/// macros::test(|cx| {
23///     let lit = cx.ident("foo")?;
24///     assert!(matches!(lit, ast::Ident { .. }));
25///     Ok(())
26/// })?;
27/// # Ok::<_, rune::support::Error>(())
28/// ```
29#[derive(Debug, TryClone, Clone, Copy, PartialEq, Eq, Spanned)]
30#[try_clone(copy)]
31#[non_exhaustive]
32pub struct Ident {
33    /// The span of the identifier.
34    pub span: Span,
35    /// The kind of the identifier.
36    #[rune(skip)]
37    pub source: ast::LitSource,
38}
39
40impl ToAst for Ident {
41    fn to_ast(span: Span, kind: ast::Kind) -> Result<Self> {
42        match kind {
43            K![ident(source)] => Ok(Self { span, source }),
44            _ => Err(compile::Error::expected(
45                ast::Token { span, kind },
46                Self::into_expectation(),
47            )),
48        }
49    }
50
51    #[inline]
52    fn matches(kind: &ast::Kind) -> bool {
53        matches!(kind, K![ident])
54    }
55
56    #[inline]
57    fn into_expectation() -> Expectation {
58        Expectation::Description("an identifier")
59    }
60}
61
62impl Parse for Ident {
63    #[inline]
64    fn parse(parser: &mut Parser<'_>) -> Result<Self> {
65        let t = parser.next()?;
66        Ident::to_ast(t.span, t.kind)
67    }
68}
69
70impl Peek for Ident {
71    fn peek(p: &mut Peeker<'_>) -> bool {
72        matches!(p.nth(0), K![ident])
73    }
74}
75
76impl<'a> Resolve<'a> for Ident {
77    type Output = &'a str;
78
79    fn resolve(&self, cx: ResolveContext<'a>) -> Result<&'a str> {
80        let span = self.span;
81
82        match self.source {
83            ast::LitSource::Text(source_id) => {
84                let ident = cx
85                    .sources
86                    .source(source_id, span)
87                    .ok_or_else(|| compile::Error::new(span, ErrorKind::BadSlice))?;
88
89                Ok(ident)
90            }
91            ast::LitSource::Synthetic(id) => {
92                let ident = cx.storage.get_string(id).ok_or_else(|| {
93                    compile::Error::new(
94                        span,
95                        ErrorKind::BadSyntheticId {
96                            kind: SyntheticKind::Label,
97                            id,
98                        },
99                    )
100                })?;
101
102                Ok(ident)
103            }
104            ast::LitSource::BuiltIn(builtin) => Ok(builtin.as_str()),
105        }
106    }
107}
108
109impl ToTokens for Ident {
110    fn to_tokens(
111        &self,
112        _: &mut MacroContext<'_, '_, '_>,
113        stream: &mut TokenStream,
114    ) -> alloc::Result<()> {
115        stream.push(ast::Token {
116            span: self.span,
117            kind: ast::Kind::Ident(self.source),
118        })
119    }
120}