boa_ast/expression/operator/
conditional.rs

1use crate::{
2    expression::Expression,
3    try_break,
4    visitor::{VisitWith, Visitor, VisitorMut},
5};
6use boa_interner::{Interner, ToInternedString};
7use core::ops::ControlFlow;
8
9/// The `conditional` (ternary) operation is the only ECMAScript operation that takes three
10/// operands.
11///
12/// This operation takes three operands: a condition followed by a question mark (`?`),
13/// then an expression to execute `if` the condition is truthy followed by a colon (`:`),
14/// and finally the expression to execute if the condition is `false`.
15/// This operator is frequently used as a shortcut for the `if` statement.
16///
17/// More information:
18///  - [ECMAScript reference][spec]
19///  - [MDN documentation][mdn]
20///
21/// [spec]: https://tc39.es/ecma262/#prod-ConditionalExpression
22/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Grammar_and_types#Literals
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 Conditional {
27    condition: Box<Expression>,
28    if_true: Box<Expression>,
29    if_false: Box<Expression>,
30}
31
32impl Conditional {
33    /// Gets the condition of the `Conditional` expression.
34    #[inline]
35    #[must_use]
36    pub const fn condition(&self) -> &Expression {
37        &self.condition
38    }
39
40    /// Gets the expression returned if `condition` is truthy.
41    #[inline]
42    #[must_use]
43    pub const fn if_true(&self) -> &Expression {
44        &self.if_true
45    }
46
47    /// Gets the expression returned if `condition` is falsy.
48    #[inline]
49    #[must_use]
50    pub const fn if_false(&self) -> &Expression {
51        &self.if_false
52    }
53
54    /// Creates a `Conditional` AST Expression.
55    #[inline]
56    #[must_use]
57    pub fn new(condition: Expression, if_true: Expression, if_false: Expression) -> Self {
58        Self {
59            condition: Box::new(condition),
60            if_true: Box::new(if_true),
61            if_false: Box::new(if_false),
62        }
63    }
64}
65
66impl ToInternedString for Conditional {
67    #[inline]
68    fn to_interned_string(&self, interner: &Interner) -> String {
69        format!(
70            "{} ? {} : {}",
71            self.condition().to_interned_string(interner),
72            self.if_true().to_interned_string(interner),
73            self.if_false().to_interned_string(interner)
74        )
75    }
76}
77
78impl From<Conditional> for Expression {
79    #[inline]
80    fn from(cond_op: Conditional) -> Self {
81        Self::Conditional(cond_op)
82    }
83}
84
85impl VisitWith for Conditional {
86    fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
87    where
88        V: Visitor<'a>,
89    {
90        try_break!(visitor.visit_expression(&self.condition));
91        try_break!(visitor.visit_expression(&self.if_true));
92        visitor.visit_expression(&self.if_false)
93    }
94
95    fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
96    where
97        V: VisitorMut<'a>,
98    {
99        try_break!(visitor.visit_expression_mut(&mut self.condition));
100        try_break!(visitor.visit_expression_mut(&mut self.if_true));
101        visitor.visit_expression_mut(&mut self.if_false)
102    }
103}