Skip to main content

boa_ast/expression/operator/update/
mod.rs

1//! Update expression nodes.
2//!
3//! A update expression increments or decrements it's operand and returns a value
4//!
5//! - [Increment and decrement operations][mdn] (`++`, `--`).
6//!
7//! The full list of valid update operators is defined in [`UpdateOp`].
8//!
9//! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators#increment_and_decrement
10mod op;
11
12use crate::{
13    Expression, Span, Spanned,
14    expression::{Identifier, access::PropertyAccess},
15    visitor::{VisitWith, Visitor, VisitorMut},
16};
17use boa_interner::{Interner, ToInternedString};
18use core::ops::ControlFlow;
19
20pub use op::*;
21
22/// A update expression is an operation with only one operand.
23///
24/// More information:
25///  - [ECMAScript reference][spec]
26///  - [MDN documentation][mdn]
27///
28/// [spec]: https://tc39.es/ecma262/#prod-UpdateExpression
29/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators#increment_and_decrement
30#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
31#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
32#[derive(Clone, Debug, PartialEq)]
33pub struct Update {
34    op: UpdateOp,
35    target: Box<UpdateTarget>,
36    span: Span,
37}
38
39impl Update {
40    /// Creates a new `Update` AST expression.
41    #[inline]
42    #[must_use]
43    pub fn new(op: UpdateOp, target: UpdateTarget, span: Span) -> Self {
44        Self {
45            op,
46            target: Box::new(target),
47            span,
48        }
49    }
50
51    /// Gets the update operation of the expression.
52    #[inline]
53    #[must_use]
54    pub const fn op(&self) -> UpdateOp {
55        self.op
56    }
57
58    /// Gets the target of this update operator.
59    #[inline]
60    #[must_use]
61    pub fn target(&self) -> &UpdateTarget {
62        self.target.as_ref()
63    }
64}
65
66impl Spanned for Update {
67    #[inline]
68    fn span(&self) -> Span {
69        self.span
70    }
71}
72
73impl ToInternedString for Update {
74    #[inline]
75    fn to_interned_string(&self, interner: &Interner) -> String {
76        match self.op {
77            UpdateOp::IncrementPost | UpdateOp::DecrementPost => {
78                format!("{}{}", self.target.to_interned_string(interner), self.op)
79            }
80            UpdateOp::IncrementPre | UpdateOp::DecrementPre => {
81                format!("{}{}", self.op, self.target.to_interned_string(interner))
82            }
83        }
84    }
85}
86
87impl From<Update> for Expression {
88    #[inline]
89    fn from(op: Update) -> Self {
90        Self::Update(op)
91    }
92}
93
94impl VisitWith for Update {
95    fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
96    where
97        V: Visitor<'a>,
98    {
99        match self.target.as_ref() {
100            UpdateTarget::Identifier(ident) => visitor.visit_identifier(ident),
101            UpdateTarget::PropertyAccess(access) => visitor.visit_property_access(access),
102        }
103    }
104
105    fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
106    where
107        V: VisitorMut<'a>,
108    {
109        match &mut *self.target {
110            UpdateTarget::Identifier(ident) => visitor.visit_identifier_mut(ident),
111            UpdateTarget::PropertyAccess(access) => visitor.visit_property_access_mut(access),
112        }
113    }
114}
115
116/// A update expression can only be performed on identifier expressions or property access expressions.
117///
118/// More information:
119///  - [ECMAScript reference][spec]
120///  - [MDN documentation][mdn]
121///
122/// [spec]: https://tc39.es/ecma262/#prod-UpdateExpression
123/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators#increment_and_decrement
124#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
125#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
126#[derive(Clone, Debug, PartialEq)]
127pub enum UpdateTarget {
128    /// An [`Identifier`] expression.
129    Identifier(Identifier),
130
131    /// An [`PropertyAccess`] expression.
132    PropertyAccess(PropertyAccess),
133}
134
135impl ToInternedString for UpdateTarget {
136    #[inline]
137    fn to_interned_string(&self, interner: &Interner) -> String {
138        match self {
139            Self::Identifier(identifier) => identifier.to_interned_string(interner),
140            Self::PropertyAccess(access) => access.to_interned_string(interner),
141        }
142    }
143}