Skip to main content

boa_ast/expression/
yield.rs

1use boa_interner::{Interner, ToInternedString};
2use core::ops::ControlFlow;
3
4use crate::{
5    Span, Spanned,
6    visitor::{VisitWith, Visitor, VisitorMut},
7};
8
9use super::Expression;
10
11/// The `yield` keyword is used to pause and resume a generator function
12///
13/// More information:
14///  - [ECMAScript reference][spec]
15///  - [MDN documentation][mdn]
16///
17/// [spec]: https://tc39.es/ecma262/#prod-YieldExpression
18/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/yield
19#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
20#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
21#[derive(Clone, Debug, PartialEq)]
22pub struct Yield {
23    target: Option<Box<Expression>>,
24    delegate: bool,
25    span: Span,
26}
27
28impl Yield {
29    /// Creates a [`Yield`] AST Expression.
30    #[inline]
31    #[must_use]
32    pub fn new(expr: Option<Expression>, delegate: bool, span: Span) -> Self {
33        Self {
34            target: expr.map(Box::new),
35            delegate,
36            span,
37        }
38    }
39
40    /// Gets the target expression of this `Yield` statement.
41    #[inline]
42    pub fn target(&self) -> Option<&Expression> {
43        self.target.as_ref().map(Box::as_ref)
44    }
45
46    /// Returns `true` if this `Yield` statement delegates to another generator or iterable object.
47    #[inline]
48    #[must_use]
49    pub const fn delegate(&self) -> bool {
50        self.delegate
51    }
52}
53
54impl Spanned for Yield {
55    #[inline]
56    fn span(&self) -> Span {
57        self.span
58    }
59}
60
61impl From<Yield> for Expression {
62    #[inline]
63    fn from(r#yield: Yield) -> Self {
64        Self::Yield(r#yield)
65    }
66}
67
68impl ToInternedString for Yield {
69    #[inline]
70    fn to_interned_string(&self, interner: &Interner) -> String {
71        let y = if self.delegate { "yield*" } else { "yield" };
72        if let Some(ex) = self.target() {
73            format!("{y} {}", ex.to_interned_string(interner))
74        } else {
75            y.to_owned()
76        }
77    }
78}
79
80impl VisitWith for Yield {
81    fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
82    where
83        V: Visitor<'a>,
84    {
85        if let Some(expr) = &self.target {
86            visitor.visit_expression(expr)
87        } else {
88            ControlFlow::Continue(())
89        }
90    }
91
92    fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
93    where
94        V: VisitorMut<'a>,
95    {
96        if let Some(expr) = &mut self.target {
97            visitor.visit_expression_mut(expr)
98        } else {
99            ControlFlow::Continue(())
100        }
101    }
102}