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