boa/syntax/ast/node/conditional/conditional_op/
mod.rs

1use crate::{
2    exec::Executable,
3    gc::{Finalize, Trace},
4    syntax::ast::node::Node,
5    Context, JsResult, JsValue,
6};
7use std::fmt;
8
9#[cfg(feature = "deser")]
10use serde::{Deserialize, Serialize};
11
12/// The `conditional` (ternary) operator is the only JavaScript operator that takes three
13/// operands.
14///
15/// This operator is the only JavaScript operator that takes three operands: a condition
16/// followed by a question mark (`?`), then an expression to execute `if` the condition is
17/// truthy followed by a colon (`:`), and finally the expression to execute if the condition
18/// is `false`. This operator is frequently used as a shortcut for the `if` statement.
19///
20/// More information:
21///  - [ECMAScript reference][spec]
22///  - [MDN documentation][mdn]
23///
24/// [spec]: https://tc39.es/ecma262/#prod-ConditionalExpression
25/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Grammar_and_types#Literals
26#[cfg_attr(feature = "deser", derive(Serialize, Deserialize))]
27#[derive(Clone, Debug, Trace, Finalize, PartialEq)]
28pub struct ConditionalOp {
29    condition: Box<Node>,
30    if_true: Box<Node>,
31    if_false: Box<Node>,
32}
33
34impl ConditionalOp {
35    pub fn cond(&self) -> &Node {
36        &self.condition
37    }
38
39    pub fn if_true(&self) -> &Node {
40        &self.if_true
41    }
42
43    pub fn if_false(&self) -> &Node {
44        &self.if_false
45    }
46
47    /// Creates a `ConditionalOp` AST node.
48    pub fn new<C, T, F>(condition: C, if_true: T, if_false: F) -> Self
49    where
50        C: Into<Node>,
51        T: Into<Node>,
52        F: Into<Node>,
53    {
54        Self {
55            condition: Box::new(condition.into()),
56            if_true: Box::new(if_true.into()),
57            if_false: Box::new(if_false.into()),
58        }
59    }
60}
61
62impl Executable for ConditionalOp {
63    fn run(&self, context: &mut Context) -> JsResult<JsValue> {
64        Ok(if self.cond().run(context)?.to_boolean() {
65            self.if_true().run(context)?
66        } else {
67            self.if_false().run(context)?
68        })
69    }
70}
71
72impl fmt::Display for ConditionalOp {
73    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
74        write!(
75            f,
76            "{} ? {} : {}",
77            self.cond(),
78            self.if_true(),
79            self.if_false()
80        )
81    }
82}
83
84impl From<ConditionalOp> for Node {
85    fn from(cond_op: ConditionalOp) -> Node {
86        Self::ConditionalOp(cond_op)
87    }
88}