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