1use crate::ast::prelude::*;
2
3#[test]
4#[cfg(not(miri))]
5fn ast_parse() {
6 rt::<ast::Path>("foo::bar");
7 rt::<ast::Path>("Self::bar");
8 rt::<ast::Path>("self::bar");
9 rt::<ast::Path>("crate::bar");
10 rt::<ast::Path>("super::bar");
11 rt::<ast::Path>("HashMap::<Foo, Bar>");
12 rt::<ast::Path>("super::HashMap::<Foo, Bar>");
13}
14
15#[derive(Debug, TryClone, PartialEq, Eq, Parse, ToTokens, Spanned)]
17#[non_exhaustive]
18pub struct Path {
19 #[rune(iter)]
21 pub global: Option<T![::]>,
22 pub first: PathSegment,
24 #[rune(iter)]
26 pub rest: Vec<(T![::], PathSegment)>,
27 #[rune(iter)]
29 pub trailing: Option<T![::]>,
30 #[rune(skip)]
32 pub(crate) id: ItemId,
33}
34
35impl Path {
36 pub(crate) fn try_as_ident(&self) -> Option<&ast::Ident> {
41 if self.rest.is_empty() && self.trailing.is_none() && self.global.is_none() {
42 self.first.try_as_ident()
43 } else {
44 None
45 }
46 }
47}
48
49impl Peek for Path {
50 fn peek(p: &mut Peeker<'_>) -> bool {
51 matches!(p.nth(0), K![::]) || PathSegment::peek(p)
52 }
53}
54
55impl IntoExpectation for &Path {
56 fn into_expectation(self) -> Expectation {
57 Expectation::Description("path")
58 }
59}
60
61impl Resolve<'_> for Path {
63 type Output = Box<str>;
64
65 fn resolve(&self, cx: ResolveContext<'_, '_>) -> Result<Self::Output> {
66 let mut buf = String::new();
67
68 if self.global.is_some() {
69 buf.try_push_str("::")?;
70 }
71
72 match &self.first {
73 PathSegment::SelfType(_) => {
74 buf.try_push_str("Self")?;
75 }
76 PathSegment::SelfValue(_) => {
77 buf.try_push_str("self")?;
78 }
79 PathSegment::Ident(ident) => {
80 buf.try_push_str(ident.resolve(cx)?)?;
81 }
82 PathSegment::Crate(_) => {
83 buf.try_push_str("crate")?;
84 }
85 PathSegment::Super(_) => {
86 buf.try_push_str("super")?;
87 }
88 PathSegment::Generics(_) => {
89 buf.try_push_str("<*>")?;
90 }
91 }
92
93 for (_, segment) in &self.rest {
94 buf.try_push_str("::")?;
95
96 match segment {
97 PathSegment::SelfType(_) => {
98 buf.try_push_str("Self")?;
99 }
100 PathSegment::SelfValue(_) => {
101 buf.try_push_str("self")?;
102 }
103 PathSegment::Ident(ident) => {
104 buf.try_push_str(ident.resolve(cx)?)?;
105 }
106 PathSegment::Crate(_) => {
107 buf.try_push_str("crate")?;
108 }
109 PathSegment::Super(_) => {
110 buf.try_push_str("super")?;
111 }
112 PathSegment::Generics(_) => {
113 buf.try_push_str("<*>")?;
114 }
115 }
116 }
117
118 if self.trailing.is_some() {
119 buf.try_push_str("::")?;
120 }
121
122 Ok(buf.try_into_boxed_str()?)
123 }
124}
125
126#[derive(Debug, TryClone, Clone, Copy, PartialEq, Eq)]
128#[try_clone(copy)]
129#[non_exhaustive]
130pub enum PathKind<'a> {
131 SelfValue,
133 Ident(&'a ast::Ident),
135}
136
137#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)]
139#[non_exhaustive]
140pub enum PathSegment {
141 SelfType(T![Self]),
143 SelfValue(T![self]),
145 Ident(ast::Ident),
147 Crate(T![crate]),
149 Super(T![super]),
151 Generics(ast::AngleBracketed<PathSegmentExpr, T![,]>),
153}
154
155impl PathSegment {
156 pub(crate) fn try_as_ident(&self) -> Option<&ast::Ident> {
161 if let PathSegment::Ident(ident) = self {
162 Some(ident)
163 } else {
164 None
165 }
166 }
167}
168
169impl IntoExpectation for PathSegment {
170 fn into_expectation(self) -> Expectation {
171 Expectation::Description("path segment")
172 }
173}
174
175impl Parse for PathSegment {
176 fn parse(p: &mut Parser<'_>) -> Result<Self> {
177 let segment = match p.nth(0)? {
178 K![Self] => Self::SelfType(p.parse()?),
179 K![self] => Self::SelfValue(p.parse()?),
180 K![ident] => Self::Ident(p.parse()?),
181 K![crate] => Self::Crate(p.parse()?),
182 K![super] => Self::Super(p.parse()?),
183 K![<] => Self::Generics(p.parse()?),
184 _ => {
185 return Err(compile::Error::expected(p.tok_at(0)?, "path segment"));
186 }
187 };
188
189 Ok(segment)
190 }
191}
192
193impl Peek for PathSegment {
194 fn peek(p: &mut Peeker<'_>) -> bool {
195 matches!(
196 p.nth(0),
197 K![<] | K![Self] | K![self] | K![crate] | K![super] | K![ident]
198 )
199 }
200}
201
202#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)]
204#[non_exhaustive]
205pub struct PathSegmentExpr {
206 pub expr: ast::Expr,
208}
209
210impl Parse for PathSegmentExpr {
211 fn parse(p: &mut Parser<'_>) -> Result<Self> {
212 let expr = ast::Expr::parse_with(
213 p,
214 ast::expr::NOT_EAGER_BRACE,
215 ast::expr::NOT_EAGER_BINARY,
216 ast::expr::NOT_CALLABLE,
217 )?;
218
219 Ok(Self { expr })
220 }
221}
222
223impl Peek for PathSegmentExpr {
224 fn peek(p: &mut Peeker<'_>) -> bool {
225 ast::Expr::peek(p)
226 }
227}