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 as_kind(&self) -> Option<PathKind<'_>> {
38 if self.rest.is_empty() && self.trailing.is_none() && self.global.is_none() {
39 match &self.first {
40 PathSegment::SelfValue(..) => Some(PathKind::SelfValue),
41 PathSegment::Ident(ident) => Some(PathKind::Ident(ident)),
42 _ => None,
43 }
44 } else {
45 None
46 }
47 }
48
49 pub(crate) fn try_as_ident(&self) -> Option<&ast::Ident> {
54 if self.rest.is_empty() && self.trailing.is_none() && self.global.is_none() {
55 self.first.try_as_ident()
56 } else {
57 None
58 }
59 }
60
61 pub(crate) fn try_as_ident_generics(
63 &self,
64 ) -> Option<(
65 &ast::Ident,
66 Option<&ast::AngleBracketed<PathSegmentExpr, T![,]>>,
67 )> {
68 if self.trailing.is_none() && self.global.is_none() {
69 if let Some(ident) = self.first.try_as_ident() {
70 let generics = if let [(_, ast::PathSegment::Generics(generics))] = &self.rest[..] {
71 Some(generics)
72 } else {
73 None
74 };
75
76 return Some((ident, generics));
77 }
78 }
79
80 None
81 }
82}
83
84impl Peek for Path {
85 fn peek(p: &mut Peeker<'_>) -> bool {
86 matches!(p.nth(0), K![::]) || PathSegment::peek(p)
87 }
88}
89
90impl IntoExpectation for &Path {
91 fn into_expectation(self) -> Expectation {
92 Expectation::Description("path")
93 }
94}
95
96impl Resolve<'_> for Path {
98 type Output = Box<str>;
99
100 fn resolve(&self, cx: ResolveContext<'_>) -> Result<Self::Output> {
101 let mut buf = String::new();
102
103 if self.global.is_some() {
104 buf.try_push_str("::")?;
105 }
106
107 match &self.first {
108 PathSegment::SelfType(_) => {
109 buf.try_push_str("Self")?;
110 }
111 PathSegment::SelfValue(_) => {
112 buf.try_push_str("self")?;
113 }
114 PathSegment::Ident(ident) => {
115 buf.try_push_str(ident.resolve(cx)?)?;
116 }
117 PathSegment::Crate(_) => {
118 buf.try_push_str("crate")?;
119 }
120 PathSegment::Super(_) => {
121 buf.try_push_str("super")?;
122 }
123 PathSegment::Generics(_) => {
124 buf.try_push_str("<*>")?;
125 }
126 }
127
128 for (_, segment) in &self.rest {
129 buf.try_push_str("::")?;
130
131 match segment {
132 PathSegment::SelfType(_) => {
133 buf.try_push_str("Self")?;
134 }
135 PathSegment::SelfValue(_) => {
136 buf.try_push_str("self")?;
137 }
138 PathSegment::Ident(ident) => {
139 buf.try_push_str(ident.resolve(cx)?)?;
140 }
141 PathSegment::Crate(_) => {
142 buf.try_push_str("crate")?;
143 }
144 PathSegment::Super(_) => {
145 buf.try_push_str("super")?;
146 }
147 PathSegment::Generics(_) => {
148 buf.try_push_str("<*>")?;
149 }
150 }
151 }
152
153 if self.trailing.is_some() {
154 buf.try_push_str("::")?;
155 }
156
157 Ok(buf.try_into_boxed_str()?)
158 }
159}
160
161#[derive(Debug, TryClone, Clone, Copy, PartialEq, Eq)]
163#[try_clone(copy)]
164#[non_exhaustive]
165pub enum PathKind<'a> {
166 SelfValue,
168 Ident(&'a ast::Ident),
170}
171
172#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)]
174#[non_exhaustive]
175pub enum PathSegment {
176 SelfType(T![Self]),
178 SelfValue(T![self]),
180 Ident(ast::Ident),
182 Crate(T![crate]),
184 Super(T![super]),
186 Generics(ast::AngleBracketed<PathSegmentExpr, T![,]>),
188}
189
190impl PathSegment {
191 pub(crate) fn try_as_ident(&self) -> Option<&ast::Ident> {
196 if let PathSegment::Ident(ident) = self {
197 Some(ident)
198 } else {
199 None
200 }
201 }
202}
203
204impl IntoExpectation for PathSegment {
205 fn into_expectation(self) -> Expectation {
206 Expectation::Description("path segment")
207 }
208}
209
210impl Parse for PathSegment {
211 fn parse(p: &mut Parser<'_>) -> Result<Self> {
212 let segment = match p.nth(0)? {
213 K![Self] => Self::SelfType(p.parse()?),
214 K![self] => Self::SelfValue(p.parse()?),
215 K![ident] => Self::Ident(p.parse()?),
216 K![crate] => Self::Crate(p.parse()?),
217 K![super] => Self::Super(p.parse()?),
218 K![<] => Self::Generics(p.parse()?),
219 _ => {
220 return Err(compile::Error::expected(p.tok_at(0)?, "path segment"));
221 }
222 };
223
224 Ok(segment)
225 }
226}
227
228impl Peek for PathSegment {
229 fn peek(p: &mut Peeker<'_>) -> bool {
230 matches!(
231 p.nth(0),
232 K![<] | K![Self] | K![self] | K![crate] | K![super] | K![ident]
233 )
234 }
235}
236
237#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)]
239#[non_exhaustive]
240pub struct PathSegmentExpr {
241 pub expr: ast::Expr,
243}
244
245impl Parse for PathSegmentExpr {
246 fn parse(p: &mut Parser<'_>) -> Result<Self> {
247 let expr = ast::Expr::parse_with(
248 p,
249 ast::expr::NOT_EAGER_BRACE,
250 ast::expr::NOT_EAGER_BINARY,
251 ast::expr::NOT_CALLABLE,
252 )?;
253
254 Ok(Self { expr })
255 }
256}
257
258impl Peek for PathSegmentExpr {
259 fn peek(p: &mut Peeker<'_>) -> bool {
260 ast::Expr::peek(p)
261 }
262}