boa/syntax/ast/node/conditional/if_node/
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 `if` statement executes a statement if a specified condition is [`truthy`][truthy]. If
13/// the condition is [`falsy`][falsy], another statement can be executed.
14///
15/// Multiple `if...else` statements can be nested to create an else if clause.
16///
17/// Note that there is no elseif (in one word) keyword in JavaScript.
18///
19/// More information:
20///  - [ECMAScript reference][spec]
21///  - [MDN documentation][mdn]
22///
23/// [spec]: https://tc39.es/ecma262/#prod-IfStatement
24/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/if...else
25/// [truthy]: https://developer.mozilla.org/en-US/docs/Glossary/truthy
26/// [falsy]: https://developer.mozilla.org/en-US/docs/Glossary/falsy
27/// [expression]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Expressions
28#[cfg_attr(feature = "deser", derive(Serialize, Deserialize))]
29#[derive(Clone, Debug, Trace, Finalize, PartialEq)]
30pub struct If {
31    cond: Box<Node>,
32    body: Box<Node>,
33    else_node: Option<Box<Node>>,
34}
35
36impl If {
37    pub fn cond(&self) -> &Node {
38        &self.cond
39    }
40
41    pub fn body(&self) -> &Node {
42        &self.body
43    }
44
45    pub fn else_node(&self) -> Option<&Node> {
46        self.else_node.as_ref().map(Box::as_ref)
47    }
48
49    /// Creates an `If` AST node.
50    pub fn new<C, B, E, OE>(condition: C, body: B, else_node: OE) -> Self
51    where
52        C: Into<Node>,
53        B: Into<Node>,
54        E: Into<Node>,
55        OE: Into<Option<E>>,
56    {
57        Self {
58            cond: Box::new(condition.into()),
59            body: Box::new(body.into()),
60            else_node: else_node.into().map(E::into).map(Box::new),
61        }
62    }
63
64    pub(in crate::syntax::ast::node) fn display(
65        &self,
66        f: &mut fmt::Formatter<'_>,
67        indent: usize,
68    ) -> fmt::Result {
69        write!(f, "if ({}) ", self.cond())?;
70        match self.else_node() {
71            Some(else_e) => {
72                self.body().display(f, indent)?;
73                f.write_str(" else ")?;
74                else_e.display(f, indent)
75            }
76            None => self.body().display(f, indent),
77        }
78    }
79}
80
81impl Executable for If {
82    fn run(&self, context: &mut Context) -> JsResult<JsValue> {
83        Ok(if self.cond().run(context)?.to_boolean() {
84            self.body().run(context)?
85        } else if let Some(else_e) = self.else_node() {
86            else_e.run(context)?
87        } else {
88            JsValue::undefined()
89        })
90    }
91}
92
93impl fmt::Display for If {
94    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
95        self.display(f, 0)
96    }
97}
98
99impl From<If> for Node {
100    fn from(if_stm: If) -> Node {
101        Self::If(if_stm)
102    }
103}