Skip to main content

parser/
pattern.rs

1use anyhow::{Result, anyhow};
2use dynamic::Dynamic;
3use smol_str::SmolStr;
4
5use super::{Parser, Span, Type, expr::Expr};
6
7#[derive(Debug, Clone)]
8pub struct Pattern {
9    pub kind: PatternKind,
10    pub span: Span,
11}
12
13#[derive(Debug, Clone)]
14pub enum PatternKind {
15    Wildcard,
16    Var { idx: u32, ty: Type },
17    Ident { name: SmolStr, ty: Type },
18    Literal(Dynamic),
19    Tuple(Vec<Pattern>),
20    List { elems: Vec<Pattern>, has_rest: bool },
21    Member(Box<Pattern>, SmolStr),
22    Idx(Box<Pattern>, Expr),
23}
24
25impl Pattern {
26    pub fn new(kind: PatternKind, span: Span) -> Self {
27        Self { kind, span }
28    }
29
30    pub fn var(&self) -> Option<u32> {
31        if let PatternKind::Var { idx, .. } = &self.kind { Some(*idx) } else { None }
32    }
33
34    pub fn expr(&self) -> Result<Expr> {
35        if let PatternKind::Var { idx, .. } = &self.kind { Ok(Expr::new(super::expr::ExprKind::Var(*idx), self.span)) } else { Err(anyhow!("不是变量")) }
36    }
37}
38
39impl Parser {
40    pub fn pattern(&mut self) -> Result<Pattern> {
41        self.whitespace()?;
42        let start = self.current_pos();
43        if self.keyword("_").is_ok() {
44            Ok(Pattern::new(PatternKind::Wildcard, self.span_from(start)))
45        } else if self.just("(").is_ok() {
46            Ok(Pattern::new(PatternKind::Tuple(crate::parse_list!(self, Vec::new(), b')', b',', self.pattern()?)), self.span_from(start)))
47        } else if self.just("[").is_ok() {
48            // 手写 list 解析,处理 `..rest`。
49            let mut elems = Vec::new();
50            let mut has_rest = false;
51            self.whitespace()?;
52            if self.take(b']').is_ok() {
53                return Ok(Pattern::new(PatternKind::List { elems, has_rest }, self.span_from(start)));
54            }
55            // 第一个元素可能是 `..name` 形式(整个 list 都是 rest)。
56            if self.take(b'.').is_ok() && self.take(b'.').is_ok() {
57                self.whitespace()?;
58                let (name, ty) = self.ident_typed()?;
59                elems.push(Pattern::new(PatternKind::Ident { name, ty }, self.span_from(start)));
60                has_rest = true;
61                self.whitespace()?;
62                self.take(b']')?;
63                return Ok(Pattern::new(PatternKind::List { elems, has_rest }, self.span_from(start)));
64            }
65            elems.push(self.pattern()?);
66            self.whitespace()?;
67            if self.take(b'.').is_ok() && self.take(b'.').is_ok() {
68                self.whitespace()?;
69                let (name, ty) = self.ident_typed()?;
70                elems.push(Pattern::new(PatternKind::Ident { name, ty }, self.span_from(start)));
71                has_rest = true;
72                self.whitespace()?;
73                let _ = self.take(b','); // 容忍尾随逗号
74                self.whitespace()?;
75                self.take(b']')?;
76                return Ok(Pattern::new(PatternKind::List { elems, has_rest }, self.span_from(start)));
77            } else if self.take(b',').is_ok() {
78                loop {
79                    self.whitespace()?;
80                    if self.take(b']').is_ok() {
81                        break;
82                    }
83                    if self.take(b'.').is_ok() && self.take(b'.').is_ok() {
84                        self.whitespace()?;
85                        let (name, ty) = self.ident_typed()?;
86                        elems.push(Pattern::new(PatternKind::Ident { name, ty }, self.span_from(start)));
87                        has_rest = true;
88                        self.whitespace()?;
89                        self.take(b']')?;
90                        return Ok(Pattern::new(PatternKind::List { elems, has_rest }, self.span_from(start)));
91                    }
92                    elems.push(self.pattern()?);
93                    self.whitespace()?;
94                    if !self.take(b',').is_ok() {
95                        break;
96                    }
97                }
98            }
99            self.whitespace()?;
100            self.take(b']')?;
101            Ok(Pattern::new(PatternKind::List { elems, has_rest }, self.span_from(start)))
102        } else if let Ok(text) = self.string() {
103            Ok(Pattern::new(PatternKind::Literal(Dynamic::String(text)), self.span_from(start)))
104        } else if let Ok((name, ty)) = self.ident_typed() {
105            Ok(Pattern::new(PatternKind::Ident { name, ty }, self.span_from(start)))
106        } else {
107            Err(anyhow!("无效的模式 {:?}", String::from_utf8_lossy(&self.buf[self.pos..])))
108        }
109    }
110}