boa/syntax/ast/node/iteration/do_while_loop/
mod.rs

1use crate::{
2    exec::{Executable, InterpreterState},
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 `do...while` statement creates a loop that executes a specified statement until the
13/// test condition evaluates to false.
14///
15/// The condition is evaluated after executing the statement, resulting in the specified
16/// statement executing at least once.
17///
18/// More information:
19///  - [ECMAScript reference][spec]
20///  - [MDN documentation][mdn]
21///
22/// [spec]: https://tc39.es/ecma262/#sec-do-while-statement
23/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/do...while
24#[cfg_attr(feature = "deser", derive(Serialize, Deserialize))]
25#[derive(Clone, Debug, Trace, Finalize, PartialEq)]
26pub struct DoWhileLoop {
27    body: Box<Node>,
28    cond: Box<Node>,
29    label: Option<Box<str>>,
30}
31
32impl DoWhileLoop {
33    pub fn body(&self) -> &Node {
34        &self.body
35    }
36
37    pub fn cond(&self) -> &Node {
38        &self.cond
39    }
40
41    pub fn label(&self) -> Option<&str> {
42        self.label.as_ref().map(Box::as_ref)
43    }
44
45    pub fn set_label(&mut self, label: Box<str>) {
46        self.label = Some(label);
47    }
48
49    /// Creates a `DoWhileLoop` AST node.
50    pub fn new<B, C>(body: B, condition: C) -> Self
51    where
52        B: Into<Node>,
53        C: Into<Node>,
54    {
55        Self {
56            body: Box::new(body.into()),
57            cond: Box::new(condition.into()),
58            label: None,
59        }
60    }
61
62    pub(in crate::syntax::ast::node) fn display(
63        &self,
64        f: &mut fmt::Formatter<'_>,
65        indentation: usize,
66    ) -> fmt::Result {
67        if let Some(ref label) = self.label {
68            write!(f, "{}: ", label)?;
69        }
70        write!(f, "do ")?;
71        self.body().display(f, indentation)?;
72        write!(f, " while ({})", self.cond())
73    }
74}
75
76impl Executable for DoWhileLoop {
77    fn run(&self, context: &mut Context) -> JsResult<JsValue> {
78        let mut result;
79        loop {
80            result = self.body().run(context)?;
81            match context.executor().get_current_state() {
82                InterpreterState::Break(label) => {
83                    handle_state_with_labels!(self, label, context, break);
84                    break;
85                }
86                InterpreterState::Continue(label) => {
87                    handle_state_with_labels!(self, label, context, continue);
88                }
89                InterpreterState::Return => {
90                    return Ok(result);
91                }
92                InterpreterState::Executing => {
93                    // Continue execution.
94                }
95            }
96            if !self.cond().run(context)?.to_boolean() {
97                break;
98            }
99        }
100        Ok(result)
101    }
102}
103
104impl fmt::Display for DoWhileLoop {
105    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
106        self.display(f, 0)
107    }
108}
109
110impl From<DoWhileLoop> for Node {
111    fn from(do_while: DoWhileLoop) -> Self {
112        Self::DoWhileLoop(do_while)
113    }
114}