ezno_parser/statements/
switch_statement.rs1use iterator_endiate::EndiateIteratorExt;
2use source_map::Span;
3use tokenizer_lib::{sized_tokens::TokenEnd, Token};
4use visitable_derive::Visitable;
5
6use crate::{
7 ast::MultipleExpression, derive_ASTNode, errors::parse_lexing_error,
8 throw_unexpected_token_with_token, ASTNode, Expression, ParseOptions, StatementOrDeclaration,
9 TSXKeyword, TSXToken,
10};
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 SwitchStatement {
16 pub case: MultipleExpression,
17 pub branches: Vec<SwitchBranch>,
18 pub position: Span,
19}
20
21#[derive(Debug, PartialEq, Clone, Visitable)]
22#[apply(derive_ASTNode)]
23pub enum SwitchBranch {
24 Default(Vec<StatementOrDeclaration>),
25 Case(Expression, Vec<StatementOrDeclaration>),
26}
27
28impl ASTNode for SwitchStatement {
29 fn get_position(&self) -> Span {
30 self.position
31 }
32
33 fn from_reader(
34 reader: &mut impl tokenizer_lib::TokenReader<crate::TSXToken, crate::TokenStart>,
35 state: &mut crate::ParsingState,
36 options: &ParseOptions,
37 ) -> Result<Self, crate::ParseError> {
38 let start = state.expect_keyword(reader, TSXKeyword::Switch)?;
39
40 reader.expect_next(crate::TSXToken::OpenParentheses)?;
41 let case = MultipleExpression::from_reader(reader, state, options)?;
42 reader.expect_next(crate::TSXToken::CloseParentheses)?;
43 reader.expect_next(crate::TSXToken::OpenBrace)?;
44
45 let mut branches = Vec::new();
46
47 let close_brace_pos: TokenEnd;
49
50 loop {
51 let case: Option<Expression> = match reader.next().ok_or_else(parse_lexing_error)? {
52 Token(TSXToken::Keyword(TSXKeyword::Default), _) => {
53 reader.expect_next(TSXToken::Colon)?;
54 None
55 }
56 Token(TSXToken::Keyword(TSXKeyword::Case), _) => {
57 let case = Expression::from_reader(reader, state, options)?;
58 reader.expect_next(TSXToken::Colon)?;
59 Some(case)
60 }
61 Token(TSXToken::CloseBrace, pos) => {
62 close_brace_pos = TokenEnd::new(pos.0 + 1);
63 break;
64 }
65 token => {
66 return throw_unexpected_token_with_token(
67 token,
68 &[
69 TSXToken::Keyword(TSXKeyword::Default),
70 TSXToken::Keyword(TSXKeyword::Case),
71 TSXToken::CloseBrace,
72 ],
73 );
74 }
75 };
76
77 let mut items = Vec::new();
80 loop {
81 if let Some(Token(
82 TSXToken::Keyword(TSXKeyword::Case | TSXKeyword::Default)
83 | TSXToken::CloseBrace,
84 _,
85 )) = reader.peek()
86 {
87 break;
88 }
89 let value = StatementOrDeclaration::from_reader(reader, state, options)?;
90 if value.requires_semi_colon() {
91 let _ = crate::expect_semi_colon(
92 reader,
93 &state.line_starts,
94 value.get_position().end,
95 options,
96 )?;
97 }
98 items.push(value);
100 }
101 if let Some(case) = case {
102 branches.push(SwitchBranch::Case(case, items));
103 } else {
104 branches.push(SwitchBranch::Default(items));
105 }
106 }
107 Ok(Self { case, branches, position: start.union(close_brace_pos) })
108 }
109
110 fn to_string_from_buffer<T: source_map::ToString>(
111 &self,
112 buf: &mut T,
113 options: &crate::ToStringOptions,
114 local: crate::LocalToStringInformation,
115 ) {
116 buf.push_str("switch");
117 options.push_gap_optionally(buf);
118 buf.push('(');
119 self.case.to_string_from_buffer(buf, options, local);
120 buf.push(')');
121 options.push_gap_optionally(buf);
122 buf.push('{');
123 for branch in &self.branches {
124 if options.pretty {
125 buf.push_new_line();
126 options.add_indent(local.depth + 1, buf);
127 }
128 let local = local.next_level();
129 match branch {
130 SwitchBranch::Default(statements) => {
131 buf.push_str("default:");
132 for (at_end, stmt) in statements.iter().endiate() {
133 if options.pretty {
134 buf.push_new_line();
135 options.add_indent(local.depth + 1, buf);
136 }
137 stmt.to_string_from_buffer(buf, options, local.next_level());
138 if stmt.requires_semi_colon() {
139 buf.push(';');
140 }
141 if options.pretty && !at_end {
142 buf.push_new_line();
143 }
144 }
145 }
146 SwitchBranch::Case(case, statements) => {
147 buf.push_str("case ");
148 case.to_string_from_buffer(buf, options, local);
149 buf.push(':');
150 for (at_end, stmt) in statements.iter().endiate() {
151 if options.pretty {
152 buf.push_new_line();
153 options.add_indent(local.depth + 1, buf);
154 }
155 stmt.to_string_from_buffer(buf, options, local.next_level());
156 if stmt.requires_semi_colon() {
157 buf.push(';');
158 }
159 if options.pretty && !at_end {
160 buf.push_new_line();
161 }
162 }
163 }
164 }
165 }
166 if options.pretty {
167 buf.push_new_line();
168 options.add_indent(local.depth, buf);
169 }
170 buf.push('}');
171 }
172}