proc-macro-workshop:sorted-7
审题
// The macro won't need to define what it means for other sorts of patterns to
// be sorted. It should be fine to trigger an error if any of the patterns is
// not something that can be compared by path.
//
// Be sure that the resulting error message is understandable and placed
// correctly underlining the unsupported pattern.
#[sorted::check]
fn f(bytes: &[u8]) -> Option<u8> {
#[sorted]
match bytes {
[] => Some(0),
[a] => Some(*a),
[a, b] => Some(a + b),
_other => None,
}
}
fn main() {}
这里主要说明的是,我们只能排序能排序的。rust
的match
功能十分强大,并非只是简单的字符枚举匹配,还有很多的数据匹配。
对于这种,我们并不需要完全的支持。
题解
impl syn::visit_mut::VisitMut for MatchVisitor {
fn visit_expr_match_mut(&mut self, i: &mut syn::ExprMatch) {
let mut target_idx: isize = -1;
for (idx, attr) in i.attrs.iter().enumerate() {
if path_to_string(&attr.path) == "sorted" {
target_idx = idx as isize;
break;
}
}
if target_idx != -1 {
i.attrs.remove(target_idx as usize);
let mut match_arm_names: Vec<(String, &dyn quote::ToTokens)> = Vec::new();
for arm in i.arms.iter() {
match &arm.pat {
syn::Pat::Path(p) => {
match_arm_names.push((path_to_string(&p.path), &p.path));
}
syn::Pat::TupleStruct(p) => {
match_arm_names.push((path_to_string(&p.path), &p.path));
}
syn::Pat::Struct(p) => {
match_arm_names.push((path_to_string(&p.path), &p.path));
}
syn::Pat::Ident(p) => {
match_arm_names.push((p.ident.to_string(), &p.ident));
}
syn::Pat::Wild(p) => {
match_arm_names.push(("_".to_string(), &p.underscore_token));
}
_ => {
self.err = std::option::Option::Some(syn::Error::new_spanned(
&arm.pat,
"unsupported by #[sorted]",
));
return;
}
}
}
if let Some(e) = check_order(match_arm_names) {
self.err = std::option::Option::Some(e);
return;
}
}
syn::visit_mut::visit_expr_match_mut(self, i)
}
}
在sorted-5中我们解析其他类型的时候,最后一个分支我们提示了一个错误。
其实就是这一关的提示错误
error: unsupported by #[sorted]
--> tests/07-unrecognized-pattern.rs:12:9
|
12 | [] => Some(0),
|
虽然我是后续整理合二为一的,但是我相信,只要保持良好的编码习惯,这种错误提示的相似性甚至一致性,是必然的结果。多多努力。
本作品采用《CC 协议》,转载必须注明作者和本文链接
推荐文章: