boa/syntax/ast/node/try_node/
mod.rs1use crate::{
2 environment::{
3 declarative_environment_record::DeclarativeEnvironmentRecord,
4 lexical_environment::VariableScope,
5 },
6 exec::Executable,
7 gc::{Finalize, Trace},
8 syntax::ast::node::{Block, Identifier, Node},
9 BoaProfiler, Context, JsResult, JsValue,
10};
11use std::fmt;
12
13#[cfg(feature = "deser")]
14use serde::{Deserialize, Serialize};
15
16#[cfg(test)]
17mod tests;
18
19#[cfg_attr(feature = "deser", derive(Serialize, Deserialize))]
33#[derive(Clone, Debug, Trace, Finalize, PartialEq)]
34pub struct Try {
35 block: Block,
36 catch: Option<Catch>,
37 finally: Option<Finally>,
38}
39
40impl Try {
41 pub(in crate::syntax) fn new<B>(
43 block: B,
44 catch: Option<Catch>,
45 finally: Option<Finally>,
46 ) -> Self
47 where
48 B: Into<Block>,
49 {
50 assert!(
51 catch.is_some() || finally.is_some(),
52 "one of catch or finally must be pressent"
53 );
54
55 Self {
56 block: block.into(),
57 catch,
58 finally,
59 }
60 }
61
62 pub fn block(&self) -> &Block {
64 &self.block
65 }
66
67 pub fn catch(&self) -> Option<&Catch> {
69 self.catch.as_ref()
70 }
71
72 pub fn finally(&self) -> Option<&Block> {
74 self.finally.as_ref().map(Finally::block)
75 }
76
77 pub(in crate::syntax::ast::node) fn display(
79 &self,
80 f: &mut fmt::Formatter<'_>,
81 indentation: usize,
82 ) -> fmt::Result {
83 write!(f, "{}try ", " ".repeat(indentation))?;
84 self.block.display(f, indentation)?;
85
86 if let Some(ref catch) = self.catch {
87 catch.display(f, indentation)?;
88 }
89
90 if let Some(ref finally) = self.finally {
91 finally.display(f, indentation)?;
92 }
93 Ok(())
94 }
95}
96
97impl Executable for Try {
98 fn run(&self, context: &mut Context) -> JsResult<JsValue> {
99 let _timer = BoaProfiler::global().start_event("Try", "exec");
100 let res = self.block().run(context).map_or_else(
101 |err| {
102 if let Some(catch) = self.catch() {
103 {
104 let env = context.get_current_environment();
105 context.push_environment(DeclarativeEnvironmentRecord::new(Some(env)));
106
107 if let Some(param) = catch.parameter() {
108 context.create_mutable_binding(param, false, VariableScope::Block)?;
109 context.initialize_binding(param, err)?;
110 }
111 }
112
113 let res = catch.block().run(context);
114
115 let _ = context.pop_environment();
117
118 res
119 } else {
120 Err(err)
121 }
122 },
123 Ok,
124 );
125
126 if let Some(finally) = self.finally() {
127 finally.run(context)?;
128 }
129
130 res
131 }
132}
133
134impl fmt::Display for Try {
135 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
136 self.display(f, 0)
137 }
138}
139
140impl From<Try> for Node {
141 fn from(try_catch: Try) -> Self {
142 Self::Try(try_catch)
143 }
144}
145
146#[cfg_attr(feature = "deser", derive(Serialize, Deserialize))]
148#[derive(Clone, Debug, Trace, Finalize, PartialEq)]
149pub struct Catch {
150 parameter: Option<Identifier>,
151 block: Block,
152}
153
154impl Catch {
155 pub(in crate::syntax) fn new<OI, I, B>(parameter: OI, block: B) -> Self
157 where
158 OI: Into<Option<I>>,
159 I: Into<Identifier>,
160 B: Into<Block>,
161 {
162 Self {
163 parameter: parameter.into().map(I::into),
164 block: block.into(),
165 }
166 }
167
168 pub fn parameter(&self) -> Option<&str> {
170 self.parameter.as_ref().map(Identifier::as_ref)
171 }
172
173 pub fn block(&self) -> &Block {
175 &self.block
176 }
177
178 pub(super) fn display(&self, f: &mut fmt::Formatter<'_>, indentation: usize) -> fmt::Result {
180 f.write_str(" catch")?;
181 if let Some(ref param) = self.parameter {
182 write!(f, "({})", param)?;
183 }
184 f.write_str(" ")?;
185 self.block.display(f, indentation)
186 }
187}
188
189impl fmt::Display for Catch {
190 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
191 self.display(f, 0)
192 }
193}
194
195#[cfg_attr(feature = "deser", derive(Serialize, Deserialize))]
197#[derive(Clone, Debug, Trace, Finalize, PartialEq)]
198pub struct Finally {
199 block: Block,
200}
201
202impl Finally {
203 pub fn block(&self) -> &Block {
205 &self.block
206 }
207
208 pub(super) fn display(&self, f: &mut fmt::Formatter<'_>, indentation: usize) -> fmt::Result {
210 f.write_str(" finally ")?;
211 self.block.display(f, indentation)
212 }
213}
214
215impl<T> From<T> for Finally
216where
217 T: Into<Block>,
218{
219 fn from(block: T) -> Self {
220 Self {
221 block: block.into(),
222 }
223 }
224}