模式匹配 比 Let 更进一步
作者:Miracle
- 2025-09-23 四川
本文字数:2312 字
阅读完需:约 8 分钟

我们的目的是 解析这样的语句 let name = "zhu"
但是看到 rust 的 let (x, _) = (11, "asaas") 我们很眼红
是我们的设计开始就要做的很完整。所以我们用一个 pattern 来解析赋值语句。为以后的这种当然可以做的很简单,先支持一个标识符的。我们先用 pattern 来做,以后还可以做以后的 match。
我们定义 基础的 Pattern 枚举如下
#[derive(Debug, Clone)]
pub enum Pattern {
Wildcard, // _
Ident(SmolStr),
Literal(Dynamic), // "abc", 123, true
Tuple(Vec<Pattern>), // (a, b, c)
List { elems: Vec<Pattern>, has_rest: bool }, // [a, b, ..]
}
复制代码
有一个基础方法 判断 Pattern 是否可以作为左值 所谓的左值就是可以位于等式的左边 也就是可以被赋值的值
impl Pattern {
pub fn is_valid_lvalue(&self) -> bool {
match self {
Pattern::Ident(_) | Pattern::Wildcard => true,
Pattern::Tuple(elems) => elems.iter().all(|p| p.is_valid_lvalue()),
Pattern::List { elems, .. } => elems.iter().all(|p| p.is_valid_lvalue()),
Pattern::Literal(_) => false,
}
}
}
复制代码
这个时候我们突然发现 模式的赋值怎么办
比如说
vec 是一个数组
vec[10] = "zzz"
这是一个赋值语句 我们可以用 Pattern 来映射 但是 目前的 Pattern 是不行的 索引我们要支持 A.b 或者 X[100] 形态的 Pattern
而且关键的 能递归! x[100].y[1024] 可以支持 所以我们修改 Pattern 定义如下
最新的定义如下
pub enum Pattern {
Wildcard, // _
Ident(SmolStr),
Literal(Dynamic), // "abc", 123, true
Tuple(Vec<Pattern>), // (a, b, c)
List { elems: Vec<Pattern>, has_rest: bool }, // [a, b, ..]
Member(Box<Pattern>, SmolStr), //x.y
Idx(Box<Pattern>, Expr), // x[y]
}
impl Pattern {
pub fn is_valid_lvalue(&self) -> bool {
match self {
Self::Ident(_) | Self::Wildcard => true,
Self::Tuple(elems) => elems.iter().all(|p| p.is_valid_lvalue()),
Self::List { elems, .. } => elems.iter().all(|p| p.is_valid_lvalue()),
Self::Literal(_) => false,
Self::Member(x, _) => x.is_valid_lvalue(),
Self::Idx(x, _) => x.is_valid_lvalue(),
}
}
}
复制代码
增加解析后缀的函数
fn suffix_parser<'a>() -> impl Parser<'a, &'a str, Vec<Box<dyn Fn(Pattern) -> Pattern>>, Extra<'a>> + Clone {
let member = just('.').ignore_then(super::ident_parser()).map(|field: SmolStr| Box::new(move |base|
Pattern::Member(Box::new(base), field.clone())) as Box<dyn Fn(Pattern) -> Pattern>);
let index = just('[').ignore_then(expr_parser()).then_ignore(just(']')).map(|idx|
Box::new(move |base| Pattern::Idx(Box::new(base), idx.clone())) as Box<dyn Fn(Pattern) -> Pattern>);
choice((member, index)).repeated().collect()
}
复制代码
这里的后缀和在你的后缀和表达式里面的后缀。是完全不同的两个概念。因为这个模式匹配有很多。不同的限制措施。所以我们这里面不去复用,而且这个代码不是多复杂。所以我们不去复用。这个一眼就能看明白 我们就不多做解释了
use super::{ident_parser, rust_ws, literal::{number_parser, string_parser, const_value_parser}};
pub(crate) fn pattern_parser<'a>() -> impl Parser<'a, &'a str, Pattern, Extra<'a>> + Clone {
recursive::<'a, 'a, &'a str, Pattern, Extra<'a>, _, _>(|pat| {
let ident_pat = just("mut").padded().or_not()
.then(ident_parser().padded_by(rust_ws())).map(|(_mut, name)| Pattern::Ident(name))
.padded_by(rust_ws()).labelled("identifier pattern");
let wild_pat = just('_').padded_by(rust_ws()).to(Pattern::Wildcard).labelled("wildcard pattern");
let lit_pat = choice((number_parser().map(|n| Pattern::Literal(n)), string_parser().map(|s|
Pattern::Literal(Dynamic::from(s))), const_value_parser().map(|c| Pattern::Literal(c)))).padded_by(rust_ws()).labelled("literal pattern");
let tuple_pat = pat.clone().separated_by(just(',').padded_by(rust_ws())).collect::<Vec<Pattern>>().delimited_by(just('(')
.padded_by(rust_ws()), just(')').padded_by(rust_ws())).map(Pattern::Tuple).labelled("tuple pattern");
let list_pat = pat.clone().separated_by(just(',').padded_by(rust_ws())).allow_trailing().collect::<Vec<Pattern>>()
.then(just("..").padded_by(rust_ws()).or_not()).map(|(elems, rest)| Pattern::List { elems, has_rest: rest.is_some() })
.delimited_by(just('[').padded_by(rust_ws()), just(']').padded_by(rust_ws())).labelled("list pattern");
choice((wild_pat, lit_pat, ident_pat, tuple_pat, list_pat)).boxed().then(suffix_parser()).map_with(|(base, suffix), _| suffix.into_iter().fold(base, |acc, f| f(acc)))
})
}
复制代码
划线
评论
复制
发布于: 刚刚阅读数: 3

Miracle
关注
三十年资深码农 2019-10-25 加入
还未添加个人简介
评论