swamp_script_analyzer/
literal.rs

1/*
2 * Copyright (c) Peter Bjorklund. All rights reserved. https://github.com/swamp/script
3 * Licensed under the MIT License. See LICENSE in the project root for license information.
4 */
5use crate::err::{Error, ErrorKind};
6use crate::{Analyzer, TypeContext};
7use swamp_script_node::Node;
8use swamp_script_semantic::ExpressionKind;
9use swamp_script_semantic::{
10    ArgumentExpressionOrLocation, EnumLiteralData, Expression, Fp, Literal,
11};
12use swamp_script_types::prelude::*;
13use tracing::error;
14
15impl Analyzer<'_> {
16    /// # Errors
17    ///
18    #[allow(clippy::too_many_lines)]
19    pub fn analyze_complex_literal_to_expression(
20        &mut self,
21        ast_node: &swamp_script_ast::Node,
22        ast_literal_kind: &swamp_script_ast::LiteralKind,
23        context: &TypeContext,
24    ) -> Result<Expression, Error> {
25        let expression = match &ast_literal_kind {
26            swamp_script_ast::LiteralKind::Slice(items) => {
27                let (encountered_element_type, resolved_items) =
28                    self.analyze_slice_type_helper(ast_node, items)?;
29
30                let slice_type = Type::Slice(Box::new(encountered_element_type.clone()));
31
32                let found_expected_type = if let Some(inner_type) = context.expected_type {
33                    inner_type.clone()
34                } else {
35                    let vec_blueprint = self
36                        .shared
37                        .core_symbol_table
38                        .get_blueprint("Vec")
39                        .unwrap()
40                        .clone();
41                    self.shared
42                        .state
43                        .instantiator
44                        .instantiate_blueprint_and_members(
45                            &vec_blueprint,
46                            &[encountered_element_type.clone()],
47                        )?
48                };
49
50                if let Some(found) = self
51                    .shared
52                    .state
53                    .instantiator
54                    .associated_impls
55                    .get_internal_member_function(&found_expected_type, "new_from_slice")
56                {
57                    let required_type = &found.signature.parameters[0].resolved_type;
58                    if resolved_items.is_empty() || slice_type.compatible_with(required_type) {
59                        let slice_literal =
60                            Literal::Slice(slice_type.clone(), resolved_items.clone());
61
62                        let expr = self.create_expr(
63                            ExpressionKind::Literal(slice_literal),
64                            slice_type.clone(),
65                            ast_node,
66                        );
67                        let return_type = *found.signature.return_type.clone();
68                        let arg = ArgumentExpressionOrLocation::Expression(expr);
69                        let call_kind = self.create_static_call(
70                            "new_from_slice",
71                            &[arg],
72                            ast_node,
73                            &found_expected_type.clone(),
74                        )?;
75
76                        self.create_expr(call_kind, return_type, ast_node)
77                    } else {
78                        error!(
79                            ?slice_type,
80                            ?required_type,
81                            "incompatible types new_from_slice"
82                        );
83                        return Err(self.create_err(
84                            ErrorKind::IncompatibleTypes {
85                                expected: required_type.clone(),
86                                found: slice_type,
87                            },
88                            ast_node,
89                        ));
90                    }
91                } else {
92                    return Err(self.create_err(
93                        ErrorKind::MissingMemberFunction("new_from_slice".to_string()),
94                        ast_node,
95                    ));
96                }
97            }
98
99            swamp_script_ast::LiteralKind::SlicePair(entries) => {
100                let (resolved_items, encountered_key_type, encountered_value_type) =
101                    self.analyze_slice_pair_literal(ast_node, entries)?;
102
103                let slice_pair_type = Type::SlicePair(
104                    Box::new(encountered_key_type.clone()),
105                    Box::new(encountered_value_type.clone()),
106                );
107
108                let found_expected_type = if let Some(inner_type) = context.expected_type {
109                    inner_type.clone()
110                } else {
111                    let map_blueprint = self
112                        .shared
113                        .core_symbol_table
114                        .get_blueprint("Map")
115                        .unwrap()
116                        .clone();
117                    self.shared
118                        .state
119                        .instantiator
120                        .instantiate_blueprint_and_members(
121                            &map_blueprint,
122                            &[encountered_key_type.clone(), encountered_value_type.clone()],
123                        )?
124                };
125
126                if let Some(found) = self
127                    .shared
128                    .state
129                    .instantiator
130                    .associated_impls
131                    .get_internal_member_function(&found_expected_type, "new_from_slice_pair")
132                {
133                    let required_type = &found.signature.parameters[0].resolved_type;
134                    if resolved_items.is_empty() || slice_pair_type.compatible_with(required_type) {
135                        let slice_literal =
136                            Literal::SlicePair(slice_pair_type.clone(), resolved_items.clone());
137
138                        let expr = self.create_expr(
139                            ExpressionKind::Literal(slice_literal),
140                            slice_pair_type.clone(),
141                            ast_node,
142                        );
143                        let return_type = *found.signature.return_type.clone();
144                        let arg = ArgumentExpressionOrLocation::Expression(expr);
145                        let call_kind = self.create_static_call(
146                            "new_from_slice_pair",
147                            &[arg],
148                            ast_node,
149                            &found_expected_type.clone(),
150                        )?;
151
152                        self.create_expr(call_kind, return_type, ast_node)
153                    } else {
154                        return Err(self.create_err(
155                            ErrorKind::IncompatibleTypes {
156                                expected: required_type.clone(),
157                                found: slice_pair_type,
158                            },
159                            ast_node,
160                        ));
161                    }
162                } else {
163                    return Err(self.create_err(
164                        ErrorKind::MissingMemberFunction("new_from_slice_pair".to_string()),
165                        ast_node,
166                    ));
167                }
168            }
169
170            _ => {
171                let (lit_kind, literal_type) =
172                    self.analyze_literal(ast_node, ast_literal_kind, context)?;
173                self.create_expr(ExpressionKind::Literal(lit_kind), literal_type, ast_node)
174            }
175        };
176
177        Ok(expression)
178    }
179
180    #[allow(clippy::too_many_lines)]
181    pub(crate) fn analyze_literal(
182        &mut self,
183        ast_node: &swamp_script_ast::Node,
184        ast_literal_kind: &swamp_script_ast::LiteralKind,
185        context: &TypeContext,
186    ) -> Result<(Literal, Type), Error> {
187        let node_text = self.get_text(ast_node);
188        let resolved_literal = match &ast_literal_kind {
189            swamp_script_ast::LiteralKind::Int => (
190                Literal::IntLiteral(Self::str_to_int(node_text).map_err(|int_conversion_err| {
191                    self.create_err(ErrorKind::IntConversionError(int_conversion_err), ast_node)
192                })?),
193                Type::Int,
194            ),
195            swamp_script_ast::LiteralKind::Float => {
196                let float = Self::str_to_float(node_text).map_err(|float_conversion_err| {
197                    self.create_err(
198                        ErrorKind::FloatConversionError(float_conversion_err),
199                        ast_node,
200                    )
201                })?;
202                (Literal::FloatLiteral(Fp::from(float)), Type::Float)
203            }
204            swamp_script_ast::LiteralKind::String(processed_string) => (
205                Literal::StringLiteral(processed_string.to_string()),
206                Type::String,
207            ),
208            swamp_script_ast::LiteralKind::Bool => {
209                let bool_val = if node_text == "false" {
210                    false
211                } else if node_text == "true" {
212                    true
213                } else {
214                    return Err(self.create_err(ErrorKind::BoolConversionError, ast_node));
215                };
216                (Literal::BoolLiteral(bool_val), Type::Bool)
217            }
218            swamp_script_ast::LiteralKind::EnumVariant(enum_literal) => {
219                let (enum_name, variant_name) = match enum_literal {
220                    swamp_script_ast::EnumVariantLiteral::Simple(enum_name, variant_name) => {
221                        (enum_name, variant_name)
222                    }
223                    swamp_script_ast::EnumVariantLiteral::Tuple(enum_name, variant_name, _) => {
224                        (enum_name, variant_name)
225                    }
226                    swamp_script_ast::EnumVariantLiteral::Struct(enum_name, variant_name, _, _) => {
227                        (enum_name, variant_name)
228                    }
229                };
230
231                let (symbol_table, name) = self.get_symbol_table_and_name(enum_name)?;
232                if let Some(enum_type_ref) = symbol_table.get_enum(&name) {
233                    let enum_type_clone = enum_type_ref.clone();
234                    let enum_type = Type::Enum(enum_type_ref.clone());
235
236                    // Handle enum variant literals in patterns
237                    let variant_ref = self.analyze_enum_variant_ref(enum_name, variant_name)?;
238
239                    let resolved_data = match enum_literal {
240                        swamp_script_ast::EnumVariantLiteral::Simple(_, _) => {
241                            EnumLiteralData::Nothing
242                        }
243                        swamp_script_ast::EnumVariantLiteral::Tuple(
244                            _node,
245                            _variant,
246                            ast_expressions,
247                        ) => {
248                            let EnumVariantType::Tuple(tuple_data) = &variant_ref else {
249                                return Err(self.create_err(
250                                    ErrorKind::WrongEnumVariantContainer(variant_ref),
251                                    &ast_node,
252                                ));
253                            };
254
255                            let resolved = self.analyze_tuple_type(
256                                &enum_literal.node(),
257                                &tuple_data.fields_in_order,
258                                ast_expressions,
259                            )?;
260                            EnumLiteralData::Tuple(resolved)
261                        }
262                        swamp_script_ast::EnumVariantLiteral::Struct(
263                            _qualified_type_identifier,
264                            variant,
265                            anonym_struct_field_and_expressions,
266                            detected_rest,
267                        ) => {
268                            if let EnumVariantType::Struct(ref resolved_variant_struct_ref) =
269                                variant_ref
270                            {
271                                if anonym_struct_field_and_expressions.len()
272                                    != resolved_variant_struct_ref
273                                        .anon_struct
274                                        .field_name_sorted_fields
275                                        .len()
276                                {
277                                    return Err(self.create_err(
278                                        ErrorKind::WrongNumberOfArguments(
279                                            anonym_struct_field_and_expressions.len(),
280                                            resolved_variant_struct_ref
281                                                .anon_struct
282                                                .field_name_sorted_fields
283                                                .len(),
284                                        ),
285                                        &variant.0,
286                                    ));
287                                }
288
289                                let resolved = self.analyze_anon_struct_instantiation(
290                                    &variant.0.clone(),
291                                    &resolved_variant_struct_ref.anon_struct,
292                                    anonym_struct_field_and_expressions,
293                                    *detected_rest,
294                                )?;
295
296                                EnumLiteralData::Struct(resolved)
297                            } else {
298                                return Err(self.create_err(
299                                    ErrorKind::WrongEnumVariantContainer(variant_ref.clone()),
300                                    &variant.0,
301                                ));
302                            }
303                        }
304                    };
305
306                    return Ok((
307                        Literal::EnumVariantLiteral(enum_type_clone, variant_ref, resolved_data),
308                        enum_type,
309                    ));
310                }
311                return Err(self.create_err(ErrorKind::UnknownEnumType, ast_node));
312            }
313
314            swamp_script_ast::LiteralKind::Tuple(expressions) => {
315                let (tuple_type_ref, resolved_items) = self.analyze_tuple_literal(expressions)?;
316                (
317                    Literal::TupleLiteral(tuple_type_ref.clone(), resolved_items),
318                    Type::Tuple(tuple_type_ref),
319                )
320            }
321            swamp_script_ast::LiteralKind::None => {
322                if let Some(found_expected_type) = context.expected_type {
323                    if let Type::Optional(_some_type) = found_expected_type {
324                        return Ok((Literal::NoneLiteral, found_expected_type.clone()));
325                    }
326                }
327                return Err(self.create_err(ErrorKind::NoneNeedsExpectedTypeHint, &ast_node));
328            }
329            &&swamp_script_ast::LiteralKind::Slice(_)
330            | &swamp_script_ast::LiteralKind::SlicePair(_) => todo!(),
331        };
332
333        Ok(resolved_literal)
334    }
335
336    fn analyze_tuple_literal(
337        &mut self,
338        items: &[swamp_script_ast::Expression],
339    ) -> Result<(Vec<Type>, Vec<Expression>), Error> {
340        let expressions = self.analyze_argument_expressions(None, items)?;
341        let mut tuple_types = Vec::new();
342        for expr in &expressions {
343            let item_type = expr.ty.clone();
344            tuple_types.push(item_type);
345        }
346
347        Ok((tuple_types, expressions))
348    }
349
350    fn analyze_tuple_type(
351        &mut self,
352        node: &swamp_script_ast::Node,
353        expected_types: &Vec<Type>,
354        ast_expressions: &Vec<swamp_script_ast::Expression>,
355    ) -> Result<Vec<Expression>, Error> {
356        if ast_expressions.len() != expected_types.len() {
357            return Err(self.create_err(ErrorKind::WrongNumberOfArguments(0, 0), node));
358        }
359
360        let mut expressions = Vec::new();
361        for (expected_type, expr) in expected_types.iter().zip(ast_expressions) {
362            let context = TypeContext::new_argument(expected_type);
363            let resolved_expr = self.analyze_expression(expr, &context)?;
364            expressions.push(resolved_expr);
365        }
366
367        Ok(expressions)
368    }
369
370    fn analyze_slice_pair_literal(
371        &mut self,
372        node: &swamp_script_ast::Node,
373        entries: &[(swamp_script_ast::Expression, swamp_script_ast::Expression)],
374    ) -> Result<(Vec<(Expression, Expression)>, Type, Type), Error> {
375        if entries.is_empty() {
376            return Ok((vec![], Type::Unit, Type::Unit));
377        }
378
379        // Resolve first entry to determine map types
380        let (first_key, first_value) = &entries[0];
381        let anything_context = TypeContext::new_anything_argument();
382        let resolved_first_key = self.analyze_expression(first_key, &anything_context)?;
383        let resolved_first_value = self.analyze_expression(first_value, &anything_context)?;
384        let key_type = resolved_first_key.ty.clone();
385        let value_type = resolved_first_value.ty.clone();
386
387        let key_context = TypeContext::new_argument(&key_type);
388        let value_context = TypeContext::new_argument(&value_type);
389
390        // Check all entries match the types
391        let mut resolved_entries = Vec::new();
392        resolved_entries.push((resolved_first_key, resolved_first_value));
393
394        for (key, value) in entries.iter().skip(1) {
395            let resolved_key = self.analyze_expression(key, &key_context)?;
396            let resolved_value = self.analyze_expression(value, &value_context)?;
397
398            if !resolved_key.ty.compatible_with(&key_type) {
399                return Err(self.create_err(
400                    ErrorKind::MapKeyTypeMismatch {
401                        expected: key_type,
402                        found: resolved_key.ty,
403                    },
404                    node,
405                ));
406            }
407
408            if !resolved_value.ty.compatible_with(&value_type) {
409                return Err(self.create_err(
410                    ErrorKind::MapValueTypeMismatch {
411                        expected: value_type,
412                        found: resolved_value.ty,
413                    },
414                    node,
415                ));
416            }
417
418            resolved_entries.push((resolved_key, resolved_value));
419        }
420
421        Ok((resolved_entries, key_type, value_type))
422    }
423
424    #[must_use]
425    pub fn create_err(&self, kind: ErrorKind, ast_node: &swamp_script_ast::Node) -> Error {
426        error!(?kind, "error created");
427        Error {
428            node: self.to_node(ast_node),
429            kind,
430        }
431    }
432
433    #[must_use]
434    pub fn create_err_resolved(&self, kind: ErrorKind, resolved_node: &Node) -> Error {
435        Error {
436            node: resolved_node.clone(),
437            kind,
438        }
439    }
440}