boa_ast/function/
class.rs

1use super::{FormalParameterList, FunctionBody, FunctionExpression};
2use crate::{
3    Declaration, LinearPosition, LinearSpan, LinearSpanIgnoreEq, Span, Spanned, block_to_string,
4    expression::{Expression, Identifier},
5    join_nodes,
6    operations::{ContainsSymbol, contains},
7    property::{MethodDefinitionKind, PropertyName},
8    scope::{FunctionScopes, Scope},
9    visitor::{VisitWith, Visitor, VisitorMut},
10};
11use boa_interner::{Interner, Sym, ToIndentedString, ToInternedString};
12use core::{fmt::Write as _, ops::ControlFlow};
13use std::hash::Hash;
14
15/// A class declaration.
16///
17/// More information:
18///  - [ECMAScript reference][spec]
19///  - [MDN documentation][mdn]
20///
21/// [spec]: https://tc39.es/ecma262/#prod-ClassDeclaration
22/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/class
23#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
24#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
25#[derive(Clone, Debug, PartialEq)]
26pub struct ClassDeclaration {
27    name: Identifier,
28    pub(crate) super_ref: Option<Expression>,
29    pub(crate) constructor: Option<FunctionExpression>,
30    pub(crate) elements: Box<[ClassElement]>,
31
32    #[cfg_attr(feature = "serde", serde(skip))]
33    pub(crate) name_scope: Scope,
34}
35
36impl ClassDeclaration {
37    /// Creates a new class declaration.
38    #[inline]
39    #[must_use]
40    pub fn new(
41        name: Identifier,
42        super_ref: Option<Expression>,
43        constructor: Option<FunctionExpression>,
44        elements: Box<[ClassElement]>,
45    ) -> Self {
46        Self {
47            name,
48            super_ref,
49            constructor,
50            elements,
51            name_scope: Scope::default(),
52        }
53    }
54
55    /// Returns the name of the class declaration.
56    #[inline]
57    #[must_use]
58    pub const fn name(&self) -> Identifier {
59        self.name
60    }
61
62    /// Returns the super class ref of the class declaration.
63    #[inline]
64    #[must_use]
65    pub const fn super_ref(&self) -> Option<&Expression> {
66        self.super_ref.as_ref()
67    }
68
69    /// Returns the constructor of the class declaration.
70    #[inline]
71    #[must_use]
72    pub const fn constructor(&self) -> Option<&FunctionExpression> {
73        self.constructor.as_ref()
74    }
75
76    /// Gets the list of all fields defined on the class declaration.
77    #[inline]
78    #[must_use]
79    pub const fn elements(&self) -> &[ClassElement] {
80        &self.elements
81    }
82
83    /// Gets the scope containing the class name binding.
84    #[inline]
85    #[must_use]
86    pub const fn name_scope(&self) -> &Scope {
87        &self.name_scope
88    }
89}
90
91impl ToIndentedString for ClassDeclaration {
92    fn to_indented_string(&self, interner: &Interner, indent_n: usize) -> String {
93        let mut buf = format!("class {}", interner.resolve_expect(self.name.sym()));
94        if let Some(super_ref) = self.super_ref.as_ref() {
95            let _ = write!(buf, " extends {}", super_ref.to_interned_string(interner));
96        }
97        if self.elements.is_empty() && self.constructor().is_none() {
98            buf.push_str(" {}");
99            return buf;
100        }
101        let indentation = "    ".repeat(indent_n + 1);
102        buf.push_str(" {\n");
103        if let Some(expr) = &self.constructor {
104            let _ = writeln!(
105                buf,
106                "{indentation}constructor({}) {}",
107                join_nodes(interner, expr.parameters().as_ref()),
108                block_to_string(&expr.body.statements, interner, indent_n + 1)
109            );
110        }
111        for element in &self.elements {
112            buf.push_str(&element.to_indented_string(interner, indent_n));
113        }
114        buf.push('}');
115        buf
116    }
117}
118
119impl VisitWith for ClassDeclaration {
120    fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
121    where
122        V: Visitor<'a>,
123    {
124        visitor.visit_identifier(&self.name)?;
125        if let Some(expr) = &self.super_ref {
126            visitor.visit_expression(expr)?;
127        }
128        if let Some(func) = &self.constructor {
129            visitor.visit_function_expression(func)?;
130        }
131        for elem in &*self.elements {
132            visitor.visit_class_element(elem)?;
133        }
134        ControlFlow::Continue(())
135    }
136
137    fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
138    where
139        V: VisitorMut<'a>,
140    {
141        visitor.visit_identifier_mut(&mut self.name)?;
142        if let Some(expr) = &mut self.super_ref {
143            visitor.visit_expression_mut(expr)?;
144        }
145        if let Some(func) = &mut self.constructor {
146            visitor.visit_function_expression_mut(func)?;
147        }
148        for elem in &mut *self.elements {
149            visitor.visit_class_element_mut(elem)?;
150        }
151        ControlFlow::Continue(())
152    }
153}
154
155impl From<ClassDeclaration> for Declaration {
156    fn from(f: ClassDeclaration) -> Self {
157        Self::ClassDeclaration(Box::new(f))
158    }
159}
160
161/// A class expression.
162///
163/// More information:
164///  - [ECMAScript reference][spec]
165///  - [MDN documentation][mdn]
166///
167/// [spec]: https://tc39.es/ecma262/#prod-ClassExpression
168/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/class
169#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
170#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
171#[derive(Clone, Debug, PartialEq)]
172pub struct ClassExpression {
173    pub(crate) name: Option<Identifier>,
174    pub(crate) super_ref: Option<Expression>,
175    pub(crate) constructor: Option<FunctionExpression>,
176    pub(crate) elements: Box<[ClassElement]>,
177
178    span: Span,
179
180    #[cfg_attr(feature = "serde", serde(skip))]
181    pub(crate) name_scope: Option<Scope>,
182}
183
184impl ClassExpression {
185    /// Creates a new class expression.
186    #[inline]
187    #[must_use]
188    pub fn new(
189        name: Option<Identifier>,
190        super_ref: Option<Expression>,
191        constructor: Option<FunctionExpression>,
192        elements: Box<[ClassElement]>,
193        has_binding_identifier: bool,
194        span: Span,
195    ) -> Self {
196        let name_scope = if has_binding_identifier {
197            Some(Scope::default())
198        } else {
199            None
200        };
201        Self {
202            name,
203            super_ref,
204            constructor,
205            elements,
206            span,
207            name_scope,
208        }
209    }
210
211    /// Returns the name of the class expression.
212    #[inline]
213    #[must_use]
214    pub const fn name(&self) -> Option<Identifier> {
215        self.name
216    }
217
218    /// Returns the super class ref of the class expression.
219    #[inline]
220    #[must_use]
221    pub const fn super_ref(&self) -> Option<&Expression> {
222        self.super_ref.as_ref()
223    }
224
225    /// Returns the constructor of the class expression.
226    #[inline]
227    #[must_use]
228    pub const fn constructor(&self) -> Option<&FunctionExpression> {
229        self.constructor.as_ref()
230    }
231
232    /// Gets the list of all fields defined on the class expression.
233    #[inline]
234    #[must_use]
235    pub const fn elements(&self) -> &[ClassElement] {
236        &self.elements
237    }
238
239    /// Gets the scope containing the class name binding if it exists.
240    #[inline]
241    #[must_use]
242    pub const fn name_scope(&self) -> Option<&Scope> {
243        self.name_scope.as_ref()
244    }
245}
246
247impl Spanned for ClassExpression {
248    #[inline]
249    fn span(&self) -> Span {
250        self.span
251    }
252}
253
254impl ToIndentedString for ClassExpression {
255    fn to_indented_string(&self, interner: &Interner, indent_n: usize) -> String {
256        let mut buf = "class".to_string();
257        if self.name_scope.is_some()
258            && let Some(name) = self.name
259        {
260            let _ = write!(buf, " {}", interner.resolve_expect(name.sym()));
261        }
262        if let Some(super_ref) = self.super_ref.as_ref() {
263            let _ = write!(buf, " extends {}", super_ref.to_interned_string(interner));
264        }
265        if self.elements.is_empty() && self.constructor().is_none() {
266            buf.push_str(" {}");
267            return buf;
268        }
269        let indentation = "    ".repeat(indent_n + 1);
270        buf.push_str(" {\n");
271        if let Some(expr) = &self.constructor {
272            let _ = writeln!(
273                buf,
274                "{indentation}constructor({}) {}",
275                join_nodes(interner, expr.parameters().as_ref()),
276                block_to_string(&expr.body.statements, interner, indent_n + 1)
277            );
278        }
279        for element in &self.elements {
280            buf.push_str(&element.to_indented_string(interner, indent_n));
281        }
282        buf.push('}');
283        buf
284    }
285}
286
287impl From<ClassExpression> for Expression {
288    fn from(expr: ClassExpression) -> Self {
289        Self::ClassExpression(Box::new(expr))
290    }
291}
292
293impl VisitWith for ClassExpression {
294    fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
295    where
296        V: Visitor<'a>,
297    {
298        if let Some(ident) = &self.name {
299            visitor.visit_identifier(ident)?;
300        }
301        if let Some(expr) = &self.super_ref {
302            visitor.visit_expression(expr)?;
303        }
304        if let Some(func) = &self.constructor {
305            visitor.visit_function_expression(func)?;
306        }
307        for elem in &*self.elements {
308            visitor.visit_class_element(elem)?;
309        }
310        ControlFlow::Continue(())
311    }
312
313    fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
314    where
315        V: VisitorMut<'a>,
316    {
317        if let Some(ident) = &mut self.name {
318            visitor.visit_identifier_mut(ident)?;
319        }
320        if let Some(expr) = &mut self.super_ref {
321            visitor.visit_expression_mut(expr)?;
322        }
323        if let Some(func) = &mut self.constructor {
324            visitor.visit_function_expression_mut(func)?;
325        }
326        for elem in &mut *self.elements {
327            visitor.visit_class_element_mut(elem)?;
328        }
329        ControlFlow::Continue(())
330    }
331}
332
333/// The body of a class' static block, as defined by the [spec].
334///
335/// Just an alias for [`Script`](crate::Script), since it has the same exact semantics.
336///
337/// [spec]: https://tc39.es/ecma262/#prod-ClassStaticBlockBody
338#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
339#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
340#[derive(Clone, Debug, PartialEq)]
341pub struct StaticBlockBody {
342    pub(crate) body: FunctionBody,
343
344    #[cfg_attr(feature = "serde", serde(skip))]
345    pub(crate) scopes: FunctionScopes,
346}
347
348impl StaticBlockBody {
349    /// Creates a new static block body.
350    #[inline]
351    #[must_use]
352    pub fn new(body: FunctionBody) -> Self {
353        Self {
354            body,
355            scopes: FunctionScopes::default(),
356        }
357    }
358
359    /// Gets the body static block.
360    #[inline]
361    #[must_use]
362    pub const fn statements(&self) -> &FunctionBody {
363        &self.body
364    }
365
366    /// Gets the scopes of the static block body.
367    #[inline]
368    #[must_use]
369    pub const fn scopes(&self) -> &FunctionScopes {
370        &self.scopes
371    }
372}
373
374/// An element that can be within a class.
375///
376/// More information:
377///  - [ECMAScript reference][spec]
378///
379/// [spec]: https://tc39.es/ecma262/#prod-ClassElement
380#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
381#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
382#[derive(Clone, Debug, PartialEq)]
383pub enum ClassElement {
384    /// A method definition.
385    MethodDefinition(ClassMethodDefinition),
386
387    /// A field definition.
388    FieldDefinition(ClassFieldDefinition),
389
390    /// A static field definition, accessible from the class constructor object
391    StaticFieldDefinition(ClassFieldDefinition),
392
393    /// A private field definition, only accessible inside the class declaration.
394    PrivateFieldDefinition(PrivateFieldDefinition),
395
396    /// A private static field definition, only accessible from static methods and fields inside the
397    /// class declaration.
398    PrivateStaticFieldDefinition(PrivateFieldDefinition),
399
400    /// A static block, where a class can have initialization logic for its static fields.
401    StaticBlock(StaticBlockBody),
402}
403
404/// A non-private class element field definition.
405///
406/// More information:
407///  - [ECMAScript reference][spec]
408///
409/// [spec]: https://tc39.es/ecma262/#prod-FieldDefinition
410#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
411#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
412#[derive(Clone, Debug, PartialEq)]
413pub struct ClassFieldDefinition {
414    pub(crate) name: PropertyName,
415    pub(crate) initializer: Option<Expression>,
416
417    #[cfg_attr(feature = "serde", serde(skip))]
418    pub(crate) scope: Scope,
419}
420
421impl ClassFieldDefinition {
422    /// Creates a new class field definition.
423    #[inline]
424    #[must_use]
425    pub fn new(name: PropertyName, initializer: Option<Expression>) -> Self {
426        Self {
427            name,
428            initializer,
429            scope: Scope::default(),
430        }
431    }
432
433    /// Returns the name of the class field definition.
434    #[inline]
435    #[must_use]
436    pub const fn name(&self) -> &PropertyName {
437        &self.name
438    }
439
440    /// Returns the initializer of the class field definition.
441    #[inline]
442    #[must_use]
443    pub const fn initializer(&self) -> Option<&Expression> {
444        self.initializer.as_ref()
445    }
446
447    /// Returns the scope of the class field definition.
448    #[inline]
449    #[must_use]
450    pub const fn scope(&self) -> &Scope {
451        &self.scope
452    }
453}
454
455/// A private class element field definition.
456///
457/// More information:
458///  - [ECMAScript reference][spec]
459///
460/// [spec]: https://tc39.es/ecma262/#prod-FieldDefinition
461#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
462#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
463#[derive(Clone, Debug, PartialEq)]
464pub struct PrivateFieldDefinition {
465    pub(crate) name: PrivateName,
466    pub(crate) initializer: Option<Expression>,
467
468    #[cfg_attr(feature = "serde", serde(skip))]
469    pub(crate) scope: Scope,
470}
471
472impl PrivateFieldDefinition {
473    /// Creates a new private field definition.
474    #[inline]
475    #[must_use]
476    pub fn new(name: PrivateName, initializer: Option<Expression>) -> Self {
477        Self {
478            name,
479            initializer,
480            scope: Scope::default(),
481        }
482    }
483
484    /// Returns the name of the private field definition.
485    #[inline]
486    #[must_use]
487    pub const fn name(&self) -> &PrivateName {
488        &self.name
489    }
490
491    /// Returns the initializer of the private field definition.
492    #[inline]
493    #[must_use]
494    pub const fn initializer(&self) -> Option<&Expression> {
495        self.initializer.as_ref()
496    }
497
498    /// Returns the scope of the private field definition.
499    #[inline]
500    #[must_use]
501    pub const fn scope(&self) -> &Scope {
502        &self.scope
503    }
504}
505
506impl ToIndentedString for ClassElement {
507    fn to_indented_string(&self, interner: &Interner, indent_n: usize) -> String {
508        let indentation = "    ".repeat(indent_n + 1);
509        match self {
510            Self::MethodDefinition(m) => m.to_indented_string(interner, indent_n),
511            Self::FieldDefinition(field) => match &field.initializer {
512                Some(expr) => {
513                    format!(
514                        "{indentation}{} = {};\n",
515                        field.name.to_interned_string(interner),
516                        expr.to_no_indent_string(interner, indent_n + 1)
517                    )
518                }
519                None => {
520                    format!(
521                        "{indentation}{};\n",
522                        field.name.to_interned_string(interner),
523                    )
524                }
525            },
526            Self::StaticFieldDefinition(field) => match &field.initializer {
527                Some(expr) => {
528                    format!(
529                        "{indentation}static {} = {};\n",
530                        field.name.to_interned_string(interner),
531                        expr.to_no_indent_string(interner, indent_n + 1)
532                    )
533                }
534                None => {
535                    format!(
536                        "{indentation}static {};\n",
537                        field.name.to_interned_string(interner),
538                    )
539                }
540            },
541            Self::PrivateFieldDefinition(PrivateFieldDefinition {
542                name, initializer, ..
543            }) => match initializer {
544                Some(expr) => {
545                    format!(
546                        "{indentation}#{} = {};\n",
547                        interner.resolve_expect(name.description()),
548                        expr.to_no_indent_string(interner, indent_n + 1)
549                    )
550                }
551                None => {
552                    format!(
553                        "{indentation}#{};\n",
554                        interner.resolve_expect(name.description()),
555                    )
556                }
557            },
558            Self::PrivateStaticFieldDefinition(PrivateFieldDefinition {
559                name,
560                initializer,
561                ..
562            }) => match initializer {
563                Some(expr) => {
564                    format!(
565                        "{indentation}static #{} = {};\n",
566                        interner.resolve_expect(name.description()),
567                        expr.to_no_indent_string(interner, indent_n + 1)
568                    )
569                }
570                None => {
571                    format!(
572                        "{indentation}static #{};\n",
573                        interner.resolve_expect(name.description()),
574                    )
575                }
576            },
577            Self::StaticBlock(block) => {
578                format!(
579                    "{indentation}static {}\n",
580                    block_to_string(&block.body.statements, interner, indent_n + 1)
581                )
582            }
583        }
584    }
585}
586
587impl VisitWith for ClassElement {
588    fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
589    where
590        V: Visitor<'a>,
591    {
592        match self {
593            Self::MethodDefinition(m) => {
594                match &m.name {
595                    ClassElementName::PropertyName(pn) => {
596                        visitor.visit_property_name(pn)?;
597                    }
598                    ClassElementName::PrivateName(pn) => {
599                        visitor.visit_private_name(pn)?;
600                    }
601                }
602                visitor.visit_formal_parameter_list(&m.parameters)?;
603                visitor.visit_function_body(&m.body)
604            }
605            Self::FieldDefinition(field) | Self::StaticFieldDefinition(field) => {
606                visitor.visit_property_name(&field.name)?;
607                if let Some(expr) = &field.initializer {
608                    visitor.visit_expression(expr)
609                } else {
610                    ControlFlow::Continue(())
611                }
612            }
613            Self::PrivateFieldDefinition(PrivateFieldDefinition {
614                name, initializer, ..
615            })
616            | Self::PrivateStaticFieldDefinition(PrivateFieldDefinition {
617                name,
618                initializer,
619                ..
620            }) => {
621                visitor.visit_private_name(name)?;
622                if let Some(expr) = initializer {
623                    visitor.visit_expression(expr)
624                } else {
625                    ControlFlow::Continue(())
626                }
627            }
628            Self::StaticBlock(block) => visitor.visit_function_body(&block.body),
629        }
630    }
631
632    fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
633    where
634        V: VisitorMut<'a>,
635    {
636        match self {
637            Self::MethodDefinition(m) => {
638                match m.name {
639                    ClassElementName::PropertyName(ref mut pn) => {
640                        visitor.visit_property_name_mut(pn)?;
641                    }
642                    ClassElementName::PrivateName(ref mut pn) => {
643                        visitor.visit_private_name_mut(pn)?;
644                    }
645                }
646                visitor.visit_formal_parameter_list_mut(&mut m.parameters)?;
647                visitor.visit_function_body_mut(&mut m.body)
648            }
649            Self::FieldDefinition(field) | Self::StaticFieldDefinition(field) => {
650                visitor.visit_property_name_mut(&mut field.name)?;
651                if let Some(expr) = &mut field.initializer {
652                    visitor.visit_expression_mut(expr)
653                } else {
654                    ControlFlow::Continue(())
655                }
656            }
657            Self::PrivateFieldDefinition(PrivateFieldDefinition {
658                name, initializer, ..
659            })
660            | Self::PrivateStaticFieldDefinition(PrivateFieldDefinition {
661                name,
662                initializer,
663                ..
664            }) => {
665                visitor.visit_private_name_mut(name)?;
666                if let Some(expr) = initializer {
667                    visitor.visit_expression_mut(expr)
668                } else {
669                    ControlFlow::Continue(())
670                }
671            }
672            Self::StaticBlock(block) => visitor.visit_function_body_mut(&mut block.body),
673        }
674    }
675}
676
677/// A method definition.
678///
679/// This type is specific to class method definitions.
680/// It includes private names and the information about whether the method is static or not.
681///
682/// More information:
683///  - [ECMAScript reference][spec]
684///
685/// [spec]: https://tc39.es/ecma262/#prod-MethodDefinition
686#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
687#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
688#[derive(Clone, Debug, PartialEq)]
689pub struct ClassMethodDefinition {
690    name: ClassElementName,
691    pub(crate) parameters: FormalParameterList,
692    pub(crate) body: FunctionBody,
693    pub(crate) contains_direct_eval: bool,
694    kind: MethodDefinitionKind,
695    is_static: bool,
696
697    #[cfg_attr(feature = "serde", serde(skip))]
698    pub(crate) scopes: FunctionScopes,
699    linear_span: LinearSpanIgnoreEq,
700}
701
702impl ClassMethodDefinition {
703    /// Creates a new class method definition.
704    #[inline]
705    #[must_use]
706    pub fn new(
707        name: ClassElementName,
708        parameters: FormalParameterList,
709        body: FunctionBody,
710        kind: MethodDefinitionKind,
711        is_static: bool,
712        start_linear_pos: LinearPosition,
713    ) -> Self {
714        let contains_direct_eval = contains(&parameters, ContainsSymbol::DirectEval)
715            || contains(&body, ContainsSymbol::DirectEval);
716
717        let linear_span = LinearSpan::new(start_linear_pos, body.linear_pos_end());
718
719        Self {
720            name,
721            parameters,
722            body,
723            contains_direct_eval,
724            kind,
725            is_static,
726            scopes: FunctionScopes::default(),
727            linear_span: linear_span.into(),
728        }
729    }
730
731    /// Returns the name of the class method definition.
732    #[inline]
733    #[must_use]
734    pub const fn name(&self) -> &ClassElementName {
735        &self.name
736    }
737
738    /// Returns the parameters of the class method definition.
739    #[inline]
740    #[must_use]
741    pub const fn parameters(&self) -> &FormalParameterList {
742        &self.parameters
743    }
744
745    /// Returns the body of the class method definition.
746    #[inline]
747    #[must_use]
748    pub const fn body(&self) -> &FunctionBody {
749        &self.body
750    }
751
752    /// Returns the kind of the class method definition.
753    #[inline]
754    #[must_use]
755    pub const fn kind(&self) -> MethodDefinitionKind {
756        self.kind
757    }
758
759    /// Returns whether the class method definition is static.
760    #[inline]
761    #[must_use]
762    pub const fn is_static(&self) -> bool {
763        self.is_static
764    }
765
766    /// Returns whether the class method definition is private.
767    #[inline]
768    #[must_use]
769    pub const fn is_private(&self) -> bool {
770        self.name.is_private()
771    }
772
773    /// Gets the scopes of the class method definition.
774    #[inline]
775    #[must_use]
776    pub const fn scopes(&self) -> &FunctionScopes {
777        &self.scopes
778    }
779
780    /// Gets linear span of the function declaration.
781    #[inline]
782    #[must_use]
783    pub const fn linear_span(&self) -> LinearSpan {
784        self.linear_span.0
785    }
786
787    /// Returns `true` if the class method definition contains a direct call to `eval`.
788    #[inline]
789    #[must_use]
790    pub const fn contains_direct_eval(&self) -> bool {
791        self.contains_direct_eval
792    }
793}
794
795impl ToIndentedString for ClassMethodDefinition {
796    fn to_indented_string(&self, interner: &Interner, indent_n: usize) -> String {
797        let indentation = "    ".repeat(indent_n + 1);
798        let prefix = match (self.is_static, &self.kind) {
799            (true, MethodDefinitionKind::Get) => "static get ",
800            (true, MethodDefinitionKind::Set) => "static set ",
801            (true, MethodDefinitionKind::Ordinary) => "static ",
802            (true, MethodDefinitionKind::Generator) => "static *",
803            (true, MethodDefinitionKind::AsyncGenerator) => "static async *",
804            (true, MethodDefinitionKind::Async) => "static async ",
805            (false, MethodDefinitionKind::Get) => "get ",
806            (false, MethodDefinitionKind::Set) => "set ",
807            (false, MethodDefinitionKind::Ordinary) => "",
808            (false, MethodDefinitionKind::Generator) => "*",
809            (false, MethodDefinitionKind::AsyncGenerator) => "async *",
810            (false, MethodDefinitionKind::Async) => "async ",
811        };
812        let name = self.name.to_interned_string(interner);
813        let parameters = join_nodes(interner, self.parameters.as_ref());
814        let body = block_to_string(&self.body.statements, interner, indent_n + 1);
815        format!("{indentation}{prefix}{name}({parameters}) {body}\n")
816    }
817}
818
819/// A class element name.
820///
821/// More information:
822///  - [ECMAScript reference][spec]
823///
824/// [spec]: https://tc39.es/ecma262/#prod-ClassElementName
825#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
826#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
827#[derive(Clone, Debug, PartialEq)]
828pub enum ClassElementName {
829    /// A property name.
830    PropertyName(PropertyName),
831
832    /// A private name.
833    PrivateName(PrivateName),
834}
835
836impl ClassElementName {
837    /// Returns whether the class element name is private.
838    #[inline]
839    #[must_use]
840    pub const fn is_private(&self) -> bool {
841        matches!(self, Self::PrivateName(_))
842    }
843}
844
845impl ToInternedString for ClassElementName {
846    fn to_interned_string(&self, interner: &Interner) -> String {
847        match &self {
848            Self::PropertyName(name) => name.to_interned_string(interner),
849            Self::PrivateName(name) => format!("#{}", interner.resolve_expect(name.description())),
850        }
851    }
852}
853
854/// A private name as defined by the [spec].
855///
856/// [spec]: https://tc39.es/ecma262/#sec-private-names
857#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
858#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
859#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
860pub struct PrivateName {
861    /// The `[[Description]]` internal slot of the private name.
862    description: Sym,
863    span: Span,
864}
865
866impl PrivateName {
867    /// Create a new private name.
868    #[inline]
869    #[must_use]
870    pub const fn new(description: Sym, span: Span) -> Self {
871        Self { description, span }
872    }
873
874    /// Get the description of the private name.
875    #[inline]
876    #[must_use]
877    pub const fn description(&self) -> Sym {
878        self.description
879    }
880}
881
882impl Spanned for PrivateName {
883    #[inline]
884    fn span(&self) -> Span {
885        self.span
886    }
887}
888
889impl VisitWith for PrivateName {
890    fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
891    where
892        V: Visitor<'a>,
893    {
894        visitor.visit_sym(&self.description)
895    }
896
897    fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
898    where
899        V: VisitorMut<'a>,
900    {
901        visitor.visit_sym_mut(&mut self.description)
902    }
903}