Skip to main content

ecma_syntax_cat/
pattern.rs

1//! Binding patterns used in destructuring, parameter lists, and
2//! variable-declarator targets.
3
4use crate::expression::{Expression, PropertyKey};
5use crate::identifier::Identifier;
6use crate::span::Spanned;
7
8/// A binding pattern paired with its source span.
9pub type Pattern = Spanned<PatternKind>;
10
11/// The shape of an ECMAScript binding pattern.
12#[derive(Debug, Clone, PartialEq, Eq)]
13pub enum PatternKind {
14    /// A plain identifier binding (`let x = ...`).
15    Identifier(Identifier),
16    /// An array-destructuring pattern (`let [a, , b, ...rest] = ...`).
17    /// `None` entries are holes; the final entry may be a `Rest` variant.
18    Array {
19        /// Element patterns; `None` for sparse holes.
20        elements: Vec<Option<Pattern>>,
21    },
22    /// An object-destructuring pattern (`let { a, b: c, ...rest } = ...`).
23    Object {
24        /// Properties and an optional final rest element.
25        properties: Vec<ObjectPatternMember>,
26    },
27    /// A rest element used inside [`PatternKind::Array`] or as the final
28    /// formal parameter (`...args`).
29    Rest {
30        /// The pattern collecting the remaining elements.
31        argument: Box<Pattern>,
32    },
33    /// A pattern with a default value, used in destructuring or as a default
34    /// formal parameter (`{ a = 1 }`, `(x = 0) =>`).
35    Assignment {
36        /// The pattern receiving the value when one is supplied.
37        left: Box<Pattern>,
38        /// The default expression to use when no value is supplied.
39        right: Box<Expression>,
40    },
41}
42
43/// One member of an object-destructuring pattern.
44#[derive(Debug, Clone, PartialEq, Eq)]
45pub enum ObjectPatternMember {
46    /// A `key: value` destructuring property.  When `shorthand` is true the
47    /// key and value are derived from the same identifier (`{ a }` rather
48    /// than `{ a: a }`); when `computed` is true the key was written in
49    /// brackets (`{ [k]: value }`).
50    Property {
51        /// The key (identifier, string, number, computed expression, or
52        /// private identifier).
53        key: PropertyKey,
54        /// The pattern receiving the corresponding value.
55        value: Pattern,
56        /// Whether the key was a computed expression (`[expr]`).
57        computed: bool,
58        /// Whether the property used shorthand (`{ a }`).
59        shorthand: bool,
60    },
61    /// A rest property (`{ ...rest }`).
62    Rest {
63        /// The pattern collecting the remaining properties.
64        argument: Pattern,
65    },
66}
67
68impl std::fmt::Display for PatternKind {
69    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
70        match self {
71            Self::Identifier(name) => write!(f, "{name}"),
72            Self::Array { elements } => write_array_pattern(f, elements),
73            Self::Object { properties } => write_object_pattern(f, properties),
74            Self::Rest { argument } => write!(f, "...{argument}"),
75            Self::Assignment { left, right } => write!(f, "{left} = {right}"),
76        }
77    }
78}
79
80fn write_array_pattern(
81    f: &mut std::fmt::Formatter<'_>,
82    elements: &[Option<Pattern>],
83) -> std::fmt::Result {
84    let body = elements
85        .iter()
86        .map(|element| {
87            element
88                .as_ref()
89                .map_or_else(String::new, |pat| format!("{pat}"))
90        })
91        .collect::<Vec<_>>()
92        .join(", ");
93    write!(f, "[{body}]")
94}
95
96fn write_object_pattern(
97    f: &mut std::fmt::Formatter<'_>,
98    properties: &[ObjectPatternMember],
99) -> std::fmt::Result {
100    let body = properties
101        .iter()
102        .map(|member| format!("{member}"))
103        .collect::<Vec<_>>()
104        .join(", ");
105    write!(f, "{{{body}}}")
106}
107
108impl std::fmt::Display for ObjectPatternMember {
109    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
110        match self {
111            Self::Property {
112                key,
113                value,
114                computed,
115                shorthand,
116            } => write_object_pattern_property(f, key, value, *computed, *shorthand),
117            Self::Rest { argument } => write!(f, "...{argument}"),
118        }
119    }
120}
121
122fn write_object_pattern_property(
123    f: &mut std::fmt::Formatter<'_>,
124    key: &PropertyKey,
125    value: &Pattern,
126    computed: bool,
127    shorthand: bool,
128) -> std::fmt::Result {
129    if shorthand {
130        write!(f, "{value}")
131    } else if computed {
132        write!(f, "[{key}]: {value}")
133    } else {
134        write!(f, "{key}: {value}")
135    }
136}