boa/syntax/ast/node/switch/
mod.rs1use crate::{
4 exec::{Executable, InterpreterState},
5 gc::{Finalize, Trace},
6 syntax::ast::node::Node,
7 Context, JsResult, JsValue,
8};
9use std::fmt;
10
11use crate::syntax::ast::node::StatementList;
12
13#[cfg(feature = "deser")]
14use serde::{Deserialize, Serialize};
15
16#[cfg(test)]
17mod tests;
18
19#[cfg_attr(feature = "deser", derive(Serialize, Deserialize))]
20#[derive(Clone, Debug, Trace, Finalize, PartialEq)]
21pub struct Case {
22 condition: Node,
23 body: StatementList,
24}
25
26impl Case {
27 pub fn new<C, B>(condition: C, body: B) -> Self
29 where
30 C: Into<Node>,
31 B: Into<StatementList>,
32 {
33 Self {
34 condition: condition.into(),
35 body: body.into(),
36 }
37 }
38
39 pub fn condition(&self) -> &Node {
41 &self.condition
42 }
43
44 pub fn body(&self) -> &StatementList {
46 &self.body
47 }
48}
49
50#[cfg_attr(feature = "deser", derive(Serialize, Deserialize))]
67#[derive(Clone, Debug, Trace, Finalize, PartialEq)]
68pub struct Switch {
69 val: Box<Node>,
70 cases: Box<[Case]>,
71 default: Option<StatementList>,
72}
73
74impl Switch {
75 pub fn new<V, C, D>(val: V, cases: C, default: Option<D>) -> Self
77 where
78 V: Into<Node>,
79 C: Into<Box<[Case]>>,
80 D: Into<StatementList>,
81 {
82 Self {
83 val: Box::new(val.into()),
84 cases: cases.into(),
85 default: default.map(D::into),
86 }
87 }
88
89 pub fn val(&self) -> &Node {
91 &self.val
92 }
93
94 pub fn cases(&self) -> &[Case] {
96 &self.cases
97 }
98
99 pub fn default(&self) -> Option<&[Node]> {
101 self.default.as_ref().map(StatementList::items)
102 }
103
104 pub(in crate::syntax::ast::node) fn display(
106 &self,
107 f: &mut fmt::Formatter<'_>,
108 indentation: usize,
109 ) -> fmt::Result {
110 let indent = " ".repeat(indentation);
111 writeln!(f, "switch ({}) {{", self.val())?;
112 for e in self.cases().iter() {
113 writeln!(f, "{} case {}:", indent, e.condition())?;
114 e.body().display(f, indentation + 2)?;
115 }
116
117 if let Some(ref default) = self.default {
118 writeln!(f, "{} default:", indent)?;
119 default.display(f, indentation + 2)?;
120 }
121 write!(f, "{}}}", indent)
122 }
123}
124
125impl Executable for Switch {
126 fn run(&self, context: &mut Context) -> JsResult<JsValue> {
127 let val = self.val().run(context)?;
128 let mut result = JsValue::null();
129 let mut matched = false;
130 context
131 .executor()
132 .set_current_state(InterpreterState::Executing);
133
134 let mut fall_through: bool = false;
137
138 for case in self.cases().iter() {
139 let cond = case.condition();
140 let block = case.body();
141 if fall_through || val.strict_equals(&cond.run(context)?) {
142 matched = true;
143 let result = block.run(context)?;
144 match context.executor().get_current_state() {
145 InterpreterState::Return => {
146 return Ok(result);
148 }
149 InterpreterState::Break(_label) => {
150 context
153 .executor()
154 .set_current_state(InterpreterState::Executing);
155 break;
156 }
157 InterpreterState::Continue(_label) => {
158 break;
160 }
161 InterpreterState::Executing => {
162 fall_through = true;
164 }
165 }
166 }
167 }
168
169 if !matched {
170 if let Some(default) = self.default() {
171 context
172 .executor()
173 .set_current_state(InterpreterState::Executing);
174 for (i, item) in default.iter().enumerate() {
175 let val = item.run(context)?;
176 match context.executor().get_current_state() {
177 InterpreterState::Return => {
178 result = val;
180 break;
181 }
182 InterpreterState::Break(_label) => {
183 break;
187 }
188 _ => {
189 }
191 }
192 if i == default.len() - 1 {
193 result = val;
194 }
195 }
196 }
197 }
198
199 Ok(result)
200 }
201}
202
203impl fmt::Display for Switch {
204 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
205 self.display(f, 0)
206 }
207}
208
209impl From<Switch> for Node {
210 fn from(switch: Switch) -> Self {
211 Self::Switch(switch)
212 }
213}