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 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 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','); 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}