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 info!(?elements, x = ?tuple_type.fields_in_order, "this is wrong");
125 if elements.len() > tuple_type.fields_in_order.len() {
126 return Err(self.create_err(
127 ErrorKind::TooManyTupleFields {
128 max: tuple_type.fields_in_order.len(),
129 got: elements.len(),
130 },
131 variant_name,
132 ));
133 }
134
135 if !scope_was_pushed {
136 self.push_block_scope("enum tuple");
137 scope_was_pushed = true;
138 }
139
140 for (element, field_type) in
142 elements.iter().zip(&tuple_type.fields_in_order)
143 {
144 match element {
145 swamp_script_ast::PatternElement::Variable(var) => {
146 if var.is_mutable.is_some() {
147 anyone_wants_mutable = true;
148 }
149 let variable_ref = self.create_local_variable(
150 &var.name,
151 var.is_mutable.as_ref(),
152 field_type,
153 )?;
154 resolved_elements
155 .push(PatternElement::Variable(variable_ref));
156 }
157 swamp_script_ast::PatternElement::Wildcard(node) => {
158 resolved_elements
159 .push(PatternElement::Wildcard(self.to_node(node)));
160 }
161 swamp_script_ast::PatternElement::Expression(expr) => {
162 return Err(self.create_err(
163 ErrorKind::ExpressionsNotAllowedInLetPattern,
164 &expr.node,
165 ));
166 }
167 }
168 }
169 }
170 EnumVariantType::Struct(struct_type) => {
171 if !scope_was_pushed {
172 self.push_block_scope("enum struct");
173 scope_was_pushed = true;
174 }
175 for element in elements {
177 match element {
178 swamp_script_ast::PatternElement::Variable(var) => {
179 let var_name_str = self.get_text(&var.name).to_string();
180 let field_index = struct_type
182 .anon_struct
183 .field_name_sorted_fields
184 .get_index(&var_name_str)
185 .ok_or_else(|| {
186 self.create_err(ErrorKind::UnknownField, &var.name)
187 })?;
188
189 let field_type = struct_type
190 .anon_struct
191 .field_name_sorted_fields
192 .get(&var_name_str)
193 .ok_or_else(|| {
194 self.create_err(ErrorKind::UnknownField, &var.name)
195 })?;
196
197 if var.is_mutable.is_some() {
198 anyone_wants_mutable = true;
199 }
200
201 let variable_ref = self.create_local_variable(
202 &var.name,
203 Option::from(&var.is_mutable),
204 &field_type.field_type,
205 )?;
206
207 resolved_elements.push(
208 PatternElement::VariableWithFieldIndex(
209 variable_ref,
210 field_index,
211 ),
212 );
213 }
214 swamp_script_ast::PatternElement::Wildcard(node) => {
215 resolved_elements
216 .push(PatternElement::Wildcard(self.to_node(node)));
217 }
218 swamp_script_ast::PatternElement::Expression(expr) => {
219 return Err(self.create_err(
220 ErrorKind::ExpressionsNotAllowedInLetPattern,
221 &expr.node,
222 ));
223 }
224 }
225 }
226 }
227 EnumVariantType::Nothing(_) => {
228 if !elements.is_empty() {
229 return Err(self
230 .create_err(ErrorKind::EnumVariantHasNoFields, variant_name));
231 }
232 }
233 }
234
235 Ok((
236 NormalPattern::EnumPattern(enum_variant_type_ref, Some(resolved_elements)),
237 scope_was_pushed,
238 anyone_wants_mutable,
239 ))
240 } else {
241 Ok((
242 NormalPattern::EnumPattern(enum_variant_type_ref, None),
243 false,
244 anyone_wants_mutable,
245 ))
246 }
247 }
248
249 swamp_script_ast::NormalPattern::Literal(ast_literal) => Ok((
250 self.analyze_pattern_literal(node, ast_literal, expected_condition_type)?,
251 false,
252 anyone_wants_mutable,
253 )),
254 }
255 }
256}