Skip to main content

ecma_syntax_cat/
class.rs

1//! Class definitions and member kinds.
2
3use crate::expression::{Expression, PropertyKey};
4use crate::function::Function;
5use crate::identifier::Identifier;
6use crate::statement::Statement;
7
8/// An ECMAScript class definition.  Shared between [`ClassDeclaration`] and
9/// [`ClassExpression`].
10///
11/// [`ClassDeclaration`]: crate::statement::StatementKind::ClassDeclaration
12/// [`ClassExpression`]: crate::expression::ExpressionKind::ClassExpression
13#[derive(Debug, Clone, PartialEq, Eq)]
14#[allow(clippy::struct_field_names)] // super_class mirrors the ESTree field name
15pub struct Class {
16    id: Option<Identifier>,
17    super_class: Option<Box<Expression>>,
18    body: Vec<ClassMember>,
19}
20
21impl Class {
22    /// Build a class definition.
23    #[must_use]
24    pub fn new(
25        id: Option<Identifier>,
26        super_class: Option<Expression>,
27        body: Vec<ClassMember>,
28    ) -> Self {
29        Self {
30            id,
31            super_class: super_class.map(Box::new),
32            body,
33        }
34    }
35
36    /// The class's name, if any.  Declarations always name it; expressions
37    /// may be anonymous.
38    #[must_use]
39    pub fn id(&self) -> Option<&Identifier> {
40        self.id.as_ref()
41    }
42
43    /// The optional `extends` clause expression.
44    #[must_use]
45    pub fn super_class(&self) -> Option<&Expression> {
46        self.super_class.as_deref()
47    }
48
49    /// The class body members in source order.
50    #[must_use]
51    pub fn body(&self) -> &[ClassMember] {
52        &self.body
53    }
54}
55
56impl std::fmt::Display for Class {
57    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
58        f.write_str("class")?;
59        if let Some(name) = &self.id {
60            write!(f, " {name}")?;
61        }
62        if let Some(super_expr) = &self.super_class {
63            write!(f, " extends {super_expr}")?;
64        }
65        f.write_str(" { ... }")
66    }
67}
68
69/// One member of a class body.
70#[derive(Debug, Clone, PartialEq, Eq)]
71pub enum ClassMember {
72    /// A method, getter, setter, or constructor.
73    Method {
74        /// The method key (identifier, string, number, computed, or private).
75        key: PropertyKey,
76        /// The function definition.
77        value: Function,
78        /// What kind of method it is.
79        kind: MethodKind,
80        /// Whether the member is `static`.
81        is_static: bool,
82        /// Whether the key was a computed expression (`[k]`).
83        computed: bool,
84    },
85    /// A field declaration (`x = 1;` or `static y = 2;`).
86    Property {
87        /// The property key.
88        key: PropertyKey,
89        /// Optional initialiser expression.
90        value: Option<Expression>,
91        /// Whether the field is `static`.
92        is_static: bool,
93        /// Whether the key was a computed expression.
94        computed: bool,
95    },
96    /// A static initialiser block (`static { ... }`).
97    StaticBlock {
98        /// Statements in the block.
99        body: Vec<Statement>,
100    },
101}
102
103/// Distinguishes the four method-like class members.
104#[derive(Debug, Clone, Copy, PartialEq, Eq)]
105pub enum MethodKind {
106    /// A constructor.
107    Constructor,
108    /// A regular method.
109    Method,
110    /// A getter (`get name() { ... }`).
111    Get,
112    /// A setter (`set name(v) { ... }`).
113    Set,
114}
115
116impl std::fmt::Display for MethodKind {
117    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
118        f.write_str(match self {
119            Self::Constructor => "constructor",
120            Self::Method => "method",
121            Self::Get => "get",
122            Self::Set => "set",
123        })
124    }
125}