1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
use proc_macro2::{Ident, Spacing, TokenTree};
/// 探测 attr 起首的 `# Path :` 路径前缀。
///
/// 规则:以 `#` + `Ident` + (`::` `Ident`)+ + `:` 形式起始时,
/// 返回 `Some((path_tokens, last_ident, 余下 tokens))`,其中
/// `path_tokens` 不含首 `#` 和尾 `:`;否则返回 `None`,
/// 调用方按原 DSL 处理整 attr。
///
/// **要求至少一个 `::`**:`#Display: ...` 不匹配(单段 trait 名
/// 通过 dummy trait ident 隐式给出,无需路径前缀)。这避免了
/// `#Display: ...` 被误识别为路径前缀而把 `Display` 吞掉的歧义。
pub(crate) fn try_parse_path_prefix(
tokens: &[TokenTree],
) -> Option<(Vec<TokenTree>, Option<Ident>, Vec<TokenTree>)> {
// 形式:# Ident (:: Ident)+ : token 数最少 5: # Ident :: Ident :
if tokens.len() < 5 {
return None;
}
if !matches!(&tokens[0], TokenTree::Punct(p) if p.as_char() == '#') {
return None;
}
if !matches!(&tokens[1], TokenTree::Ident(_)) {
return None;
}
// 状态机:
// expect_sep=true → 期待 `::`(双 `:` Punct,第二 `:` 可 Alone)
// expect_sep=false → 期待 Ident(紧跟在 `::` 之后)
// 起始:刚读完第一个 Ident,期待 `::`。
let mut i = 2usize;
let mut expect_sep = true;
let mut saw_double_colon = false;
let mut last_ident = None;
loop {
match tokens.get(i) {
// `::`:必须是连续两个 `:`,且第一个 `:` Spacing::Joint
Some(TokenTree::Punct(p)) if p.as_char() == ':' && expect_sep => {
match tokens.get(i + 1) {
Some(TokenTree::Punct(p2))
if p2.as_char() == ':' && p.spacing() == Spacing::Joint =>
{
i += 2;
expect_sep = false;
saw_double_colon = true;
}
// 单 `:` 收尾——只在已见过至少一个 `::` 时才接受
_ if saw_double_colon => {
let path = tokens[1..i].to_vec();
let rest = tokens[i + 1..].to_vec();
return Some((path, last_ident, rest));
}
// 否则 falls through 到下方 `_ => return None`
_ => return None,
}
}
// 期待的 Ident(紧跟在 `::` 之后)
Some(TokenTree::Ident(id)) if !expect_sep => {
i += 1;
last_ident = id.clone().into();
expect_sep = true;
}
_ => return None,
}
}
}