ezno_parser/statements/
try_catch_statement.rs1use crate::{
2 derive_ASTNode, ASTNode, Block, ParseError, ParseErrors, TSXKeyword, TSXToken, TypeAnnotation,
3 VariableField, WithComment,
4};
5use source_map::Span;
6use tokenizer_lib::Token;
7use visitable_derive::Visitable;
8
9#[cfg_attr(target_family = "wasm", tsify::declare)]
10pub type ExceptionVarField = WithComment<VariableField>;
11
12#[apply(derive_ASTNode)]
13#[derive(Debug, PartialEq, Clone, Visitable, get_field_by_type::GetFieldByType)]
14#[get_field_by_type_target(Span)]
15pub struct TryCatchStatement {
16 pub try_inner: Block,
17 pub catch_inner: Option<Block>,
18 pub exception_var: Option<(ExceptionVarField, Option<TypeAnnotation>)>,
19 pub finally_inner: Option<Block>,
20 pub position: Span,
21}
22
23impl ASTNode for TryCatchStatement {
24 fn get_position(&self) -> Span {
25 self.position
26 }
27
28 fn from_reader(
29 reader: &mut impl tokenizer_lib::TokenReader<TSXToken, crate::TokenStart>,
30 state: &mut crate::ParsingState,
31 options: &crate::ParseOptions,
32 ) -> Result<Self, crate::ParseError> {
33 let start = state.expect_keyword(reader, TSXKeyword::Try)?;
34 let try_inner = Block::from_reader(reader, state, options)?;
35
36 let mut catch_inner: Option<Block> = None;
37 let mut exception_var: Option<(ExceptionVarField, Option<TypeAnnotation>)> = None;
38
39 if let Some(Token(TSXToken::Keyword(TSXKeyword::Catch), _)) = reader.peek() {
41 state.append_keyword_at_pos(reader.next().unwrap().1 .0, TSXKeyword::Catch);
42
43 if let Some(Token(TSXToken::OpenParentheses, _)) = reader.peek() {
45 reader.expect_next(TSXToken::OpenParentheses)?;
46 let variable_field =
47 WithComment::<VariableField>::from_reader(reader, state, options)?;
48
49 let mut exception_var_type: Option<TypeAnnotation> = None;
51 if reader
52 .conditional_next(|tok| {
53 options.type_annotations && matches!(tok, TSXToken::Colon)
54 })
55 .is_some()
56 {
57 exception_var_type = Some(TypeAnnotation::from_reader(reader, state, options)?);
58 }
59 exception_var = Some((variable_field, exception_var_type));
60
61 reader.expect_next(TSXToken::CloseParentheses)?;
62 }
63
64 catch_inner = Some(Block::from_reader(reader, state, options)?);
65 }
66
67 let mut finally_inner: Option<Block> = None;
69 if let Some(Token(TSXToken::Keyword(TSXKeyword::Finally), _)) = reader.peek() {
70 state.append_keyword_at_pos(reader.next().unwrap().1 .0, TSXKeyword::Finally);
71 finally_inner = Some(Block::from_reader(reader, state, options)?);
72 }
73
74 let position: Span = if let Some(finally_block) = &finally_inner {
76 start.union(finally_block.get_position())
77 } else if let Some(catch_block) = &catch_inner {
78 start.union(catch_block.get_position())
79 } else {
80 return Err(ParseError::new(
82 ParseErrors::ExpectedCatchOrFinally,
83 reader.next().unwrap().get_span(),
84 ));
85 };
86
87 Ok(Self { try_inner, catch_inner, exception_var, finally_inner, position })
88 }
89
90 fn to_string_from_buffer<T: source_map::ToString>(
91 &self,
92 buf: &mut T,
93 options: &crate::ToStringOptions,
94 local: crate::LocalToStringInformation,
95 ) {
96 buf.push_str("try");
98 options.push_gap_optionally(buf);
99 self.try_inner.to_string_from_buffer(buf, options, local.next_level());
100
101 if let Some(catch) = &self.catch_inner {
103 options.push_gap_optionally(buf);
104 buf.push_str("catch");
105 options.push_gap_optionally(buf);
106
107 if let Some((exception_var, exception_var_type)) = &self.exception_var {
109 buf.push('(');
110 exception_var.to_string_from_buffer(buf, options, local);
111
112 if let Some(exception_var_type) = exception_var_type {
114 buf.push_str(": ");
115 exception_var_type.to_string_from_buffer(buf, options, local);
116 }
117 buf.push(')');
118 options.push_gap_optionally(buf);
119 }
120
121 catch.to_string_from_buffer(buf, options, local.next_level());
122 }
123
124 if let Some(finally) = &self.finally_inner {
126 options.push_gap_optionally(buf);
127 buf.push_str("finally");
128 options.push_gap_optionally(buf);
129 finally.to_string_from_buffer(buf, options, local.next_level());
130 }
131 }
132}