Skip to main content

nu_protocol/ast/
match_pattern.rs

1use super::Expression;
2use crate::{Span, Value, VarId};
3use serde::{Deserialize, Serialize};
4
5/// AST Node for match arm with optional match guard
6#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7pub struct MatchPattern {
8    pub pattern: Pattern,
9    pub guard: Option<Box<Expression>>,
10    pub span: Span,
11}
12
13impl MatchPattern {
14    pub fn variables(&self) -> Vec<VarId> {
15        self.pattern.variables()
16    }
17
18    pub fn is_wildcard(&self) -> bool {
19        self.guard.is_none() && self.pattern.is_wildcard()
20    }
21}
22
23/// AST Node for pattern matching rules
24#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
25pub enum Pattern {
26    /// Destructuring of records
27    Record(Vec<(String, MatchPattern)>),
28    /// List destructuring
29    List(Vec<MatchPattern>),
30    /// Matching against a literal (from expression result)
31    // TODO: it would be nice if this didn't depend on AST
32    // maybe const evaluation can get us to a Value instead?
33    Expression(Box<Expression>),
34    /// Matching against a literal (pure value)
35    Value(Value),
36    /// binding to a variable
37    Variable(VarId),
38    /// the `pattern1 \ pattern2` or-pattern
39    Or(Vec<MatchPattern>),
40    /// the `..$foo` pattern
41    Rest(VarId),
42    /// the `..` pattern
43    IgnoreRest,
44    /// the `_` pattern
45    IgnoreValue,
46    /// Failed parsing of a pattern
47    Garbage,
48}
49
50impl Pattern {
51    pub fn variables(&self) -> Vec<VarId> {
52        let mut output = vec![];
53        match self {
54            Pattern::Record(items) => {
55                for item in items {
56                    output.append(&mut item.1.variables());
57                }
58            }
59            Pattern::List(items) => {
60                for item in items {
61                    output.append(&mut item.variables());
62                }
63            }
64            Pattern::Variable(var_id) => output.push(*var_id),
65            Pattern::Or(patterns) => {
66                for pattern in patterns {
67                    output.append(&mut pattern.variables());
68                }
69            }
70            Pattern::Rest(var_id) => output.push(*var_id),
71            Pattern::Expression(_)
72            | Pattern::Value(_)
73            | Pattern::IgnoreValue
74            | Pattern::Garbage
75            | Pattern::IgnoreRest => {}
76        }
77
78        output
79    }
80
81    pub fn is_wildcard(&self) -> bool {
82        match self {
83            Self::Variable(_) | Self::IgnoreValue => true,
84            Self::Or(match_patterns) => match_patterns.iter().any(|x| x.is_wildcard()),
85            _ => false,
86        }
87    }
88}