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