1use crate::Analyzer;
7use crate::err::{Error, ErrorKind};
8use swamp_script_semantic::{
9 EnumVariantType, EnumVariantTypeRef, NormalPattern, Pattern, PatternElement, Type,
10};
11use tracing::info;
12
13impl Analyzer<'_> {
14 fn find_variant_in_pattern(
15 &self,
16 expression_type: &Type,
17 ast_name: &swamp_script_ast::Node,
18 ) -> Result<EnumVariantTypeRef, Error> {
19 let enum_type_ref = match expression_type {
20 Type::Enum(enum_type_ref) => enum_type_ref,
21 _ => Err(self.create_err(ErrorKind::ExpectedEnumInPattern, ast_name))?,
22 };
23
24 let variant_name = self.get_text(ast_name).to_string();
25
26 enum_type_ref
27 .borrow()
28 .get_variant(&variant_name)
29 .map_or_else(
30 || Err(self.create_err(ErrorKind::UnknownEnumVariantTypeInPattern, ast_name)),
31 |found_variant| Ok(found_variant.clone()),
32 )
33 }
34
35 pub(crate) fn analyze_pattern(
36 &mut self,
37 ast_pattern: &swamp_script_ast::Pattern,
38 expected_condition_type: &Type,
39 ) -> Result<(Pattern, bool, bool), Error> {
40 match ast_pattern {
41 swamp_script_ast::Pattern::Wildcard(node) => {
42 Ok((Pattern::Wildcard(self.to_node(node)), false, false))
43 }
44 swamp_script_ast::Pattern::NormalPattern(node, normal_pattern, maybe_guard) => {
45 let (normal_pattern, was_pushed, wanted_mutable) =
46 self.analyze_normal_pattern(node, normal_pattern, expected_condition_type)?;
47
48 let resolved_guard = if let Some(guard_clause) = maybe_guard {
49 match guard_clause {
50 swamp_script_ast::GuardClause::Wildcard(_) => None,
51 swamp_script_ast::GuardClause::Expression(clause_expr) => {
52 Some(self.analyze_bool_argument_expression(clause_expr)?)
53 }
54 }
55 } else {
56 None
57 };
58 Ok((
59 Pattern::Normal(normal_pattern, resolved_guard),
60 was_pushed,
61 wanted_mutable,
62 ))
63 }
64 }
65 }
66
67 #[allow(clippy::too_many_lines)]
68 pub(crate) fn analyze_normal_pattern(
69 &mut self,
70 node: &swamp_script_ast::Node,
71 ast_normal_pattern: &swamp_script_ast::NormalPattern,
72 expected_condition_type: &Type,
73 ) -> Result<(NormalPattern, bool, bool), Error> {
74 let mut anyone_wants_mutable = false;
75 match ast_normal_pattern {
76 swamp_script_ast::NormalPattern::PatternList(elements) => {
77 let mut resolved_elements = Vec::new();
78 let mut scope_is_pushed = false;
79 for element in elements {
80 match element {
81 swamp_script_ast::PatternElement::Variable(var) => {
82 if !scope_is_pushed {
83 self.push_block_scope("pattern_list one variable");
84 scope_is_pushed = true;
85 }
86 if var.is_mutable.is_some() {
87 anyone_wants_mutable = true;
88 }
89 let variable_ref = self.create_local_variable(
90 &var.name,
91 Option::from(&var.is_mutable),
92 expected_condition_type,
93 )?;
94 resolved_elements.push(PatternElement::Variable(variable_ref));
95 }
96 swamp_script_ast::PatternElement::Expression(expr) => {
97 return Err(self.create_err(
98 ErrorKind::ExpressionsNotAllowedInLetPattern,
99 &expr.node,
100 ));
101 }
102 swamp_script_ast::PatternElement::Wildcard(node) => {
103 resolved_elements.push(PatternElement::Wildcard(self.to_node(node)));
104 }
105 }
106 }
107 Ok((
108 NormalPattern::PatternList(resolved_elements),
109 scope_is_pushed,
110 anyone_wants_mutable,
111 ))
112 }
113
114 swamp_script_ast::NormalPattern::EnumPattern(variant_name, maybe_elements) => {
115 let mut scope_was_pushed = false;
116 let enum_variant_type_ref =
117 self.find_variant_in_pattern(expected_condition_type, variant_name)?;
118
119 if let Some(elements) = maybe_elements {
120 let mut resolved_elements = Vec::new();
121 match &*enum_variant_type_ref {
122 EnumVariantType::Tuple(tuple_type) => {
123 if elements.len() > tuple_type.fields_in_order.len() {
125 return Err(self.create_err(
126 ErrorKind::TooManyTupleFields {
127 max: tuple_type.fields_in_order.len(),
128 got: elements.len(),
129 },
130 variant_name,
131 ));
132 }
133
134 if !scope_was_pushed {
135 self.push_block_scope("enum tuple");
136 scope_was_pushed = true;
137 }
138
139 for (element, field_type) in
141 elements.iter().zip(&tuple_type.fields_in_order)
142 {
143 match element {
144 swamp_script_ast::PatternElement::Variable(var) => {
145 if var.is_mutable.is_some() {
146 anyone_wants_mutable = true;
147 }
148 let variable_ref = self.create_local_variable(
149 &var.name,
150 var.is_mutable.as_ref(),
151 field_type,
152 )?;
153 resolved_elements
154 .push(PatternElement::Variable(variable_ref));
155 }
156 swamp_script_ast::PatternElement::Wildcard(node) => {
157 resolved_elements
158 .push(PatternElement::Wildcard(self.to_node(node)));
159 }
160 swamp_script_ast::PatternElement::Expression(expr) => {
161 return Err(self.create_err(
162 ErrorKind::ExpressionsNotAllowedInLetPattern,
163 &expr.node,
164 ));
165 }
166 }
167 }
168 }
169 EnumVariantType::Struct(struct_type) => {
170 if !scope_was_pushed {
171 self.push_block_scope("enum struct");
172 scope_was_pushed = true;
173 }
174 for element in elements {
176 match element {
177 swamp_script_ast::PatternElement::Variable(var) => {
178 let var_name_str = self.get_text(&var.name).to_string();
179 let field_index = struct_type
181 .anon_struct
182 .field_name_sorted_fields
183 .get_index(&var_name_str)
184 .ok_or_else(|| {
185 self.create_err(ErrorKind::UnknownField, &var.name)
186 })?;
187
188 let field_type = struct_type
189 .anon_struct
190 .field_name_sorted_fields
191 .get(&var_name_str)
192 .ok_or_else(|| {
193 self.create_err(ErrorKind::UnknownField, &var.name)
194 })?;
195
196 if var.is_mutable.is_some() {
197 anyone_wants_mutable = true;
198 }
199
200 let variable_ref = self.create_local_variable(
201 &var.name,
202 Option::from(&var.is_mutable),
203 &field_type.field_type,
204 )?;
205
206 resolved_elements.push(
207 PatternElement::VariableWithFieldIndex(
208 variable_ref,
209 field_index,
210 ),
211 );
212 }
213 swamp_script_ast::PatternElement::Wildcard(node) => {
214 resolved_elements
215 .push(PatternElement::Wildcard(self.to_node(node)));
216 }
217 swamp_script_ast::PatternElement::Expression(expr) => {
218 return Err(self.create_err(
219 ErrorKind::ExpressionsNotAllowedInLetPattern,
220 &expr.node,
221 ));
222 }
223 }
224 }
225 }
226 EnumVariantType::Nothing(_) => {
227 if !elements.is_empty() {
228 return Err(self
229 .create_err(ErrorKind::EnumVariantHasNoFields, variant_name));
230 }
231 }
232 }
233
234 Ok((
235 NormalPattern::EnumPattern(enum_variant_type_ref, Some(resolved_elements)),
236 scope_was_pushed,
237 anyone_wants_mutable,
238 ))
239 } else {
240 Ok((
241 NormalPattern::EnumPattern(enum_variant_type_ref, None),
242 false,
243 anyone_wants_mutable,
244 ))
245 }
246 }
247
248 swamp_script_ast::NormalPattern::Literal(ast_literal) => Ok((
249 self.analyze_pattern_literal(node, ast_literal, expected_condition_type)?,
250 false,
251 anyone_wants_mutable,
252 )),
253 }
254 }
255}