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