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(slice_type, required_type.clone()),
85                            ast_node,
86                        ));
87                    }
88                } else {
89                    return Err(self.create_err(
90                        ErrorKind::MissingMemberFunction("new_from_slice".to_string()),
91                        ast_node,
92                    ));
93                }
94            }
95
96            swamp_script_ast::LiteralKind::SlicePair(entries) => {
97                let (resolved_items, encountered_key_type, encountered_value_type) =
98                    self.analyze_slice_pair_literal(ast_node, entries)?;
99
100                let slice_pair_type = Type::SlicePair(
101                    Box::new(encountered_key_type.clone()),
102                    Box::new(encountered_value_type.clone()),
103                );
104
105                let found_expected_type = if let Some(inner_type) = context.expected_type {
106                    inner_type.clone()
107                } else {
108                    let map_blueprint = self
109                        .shared
110                        .core_symbol_table
111                        .get_blueprint("Map")
112                        .unwrap()
113                        .clone();
114                    self.shared
115                        .state
116                        .instantiator
117                        .instantiate_blueprint_and_members(
118                            &map_blueprint,
119                            &[encountered_key_type.clone(), encountered_value_type.clone()],
120                        )?
121                };
122
123                if let Some(found) = self
124                    .shared
125                    .state
126                    .instantiator
127                    .associated_impls
128                    .get_internal_member_function(&found_expected_type, "new_from_slice_pair")
129                {
130                    let required_type = &found.signature.parameters[0].resolved_type;
131                    if resolved_items.is_empty() || slice_pair_type.compatible_with(required_type) {
132                        let slice_literal =
133                            Literal::SlicePair(slice_pair_type.clone(), resolved_items.clone());
134
135                        let expr = self.create_expr(
136                            ExpressionKind::Literal(slice_literal),
137                            slice_pair_type.clone(),
138                            ast_node,
139                        );
140                        let return_type = *found.signature.return_type.clone();
141                        let arg = ArgumentExpressionOrLocation::Expression(expr);
142                        let call_kind = self.create_static_call(
143                            "new_from_slice_pair",
144                            &[arg],
145                            ast_node,
146                            &found_expected_type.clone(),
147                        )?;
148
149                        self.create_expr(call_kind, return_type, ast_node)
150                    } else {
151                        return Err(self.create_err(
152                            ErrorKind::IncompatibleTypes(slice_pair_type, required_type.clone()),
153                            ast_node,
154                        ));
155                    }
156                } else {
157                    return Err(self.create_err(
158                        ErrorKind::MissingMemberFunction("new_from_slice_pair".to_string()),
159                        ast_node,
160                    ));
161                }
162            }
163
164            _ => {
165                let (lit_kind, literal_type) =
166                    self.analyze_literal(ast_node, ast_literal_kind, context)?;
167                self.create_expr(ExpressionKind::Literal(lit_kind), literal_type, ast_node)
168            }
169        };
170
171        Ok(expression)
172    }
173
174    #[allow(clippy::too_many_lines)]
175    pub(crate) fn analyze_literal(
176        &mut self,
177        ast_node: &swamp_script_ast::Node,
178        ast_literal_kind: &swamp_script_ast::LiteralKind,
179        context: &TypeContext,
180    ) -> Result<(Literal, Type), Error> {
181        let node_text = self.get_text(ast_node);
182        let resolved_literal = match &ast_literal_kind {
183            swamp_script_ast::LiteralKind::Int => (
184                Literal::IntLiteral(Self::str_to_int(node_text).map_err(|int_conversion_err| {
185                    self.create_err(ErrorKind::IntConversionError(int_conversion_err), ast_node)
186                })?),
187                Type::Int,
188            ),
189            swamp_script_ast::LiteralKind::Float => {
190                let float = Self::str_to_float(node_text).map_err(|float_conversion_err| {
191                    self.create_err(
192                        ErrorKind::FloatConversionError(float_conversion_err),
193                        ast_node,
194                    )
195                })?;
196                (Literal::FloatLiteral(Fp::from(float)), Type::Float)
197            }
198            swamp_script_ast::LiteralKind::String(processed_string) => (
199                Literal::StringLiteral(processed_string.to_string()),
200                Type::String,
201            ),
202            swamp_script_ast::LiteralKind::Bool => {
203                let bool_val = if node_text == "false" {
204                    false
205                } else if node_text == "true" {
206                    true
207                } else {
208                    return Err(self.create_err(ErrorKind::BoolConversionError, ast_node));
209                };
210                (Literal::BoolLiteral(bool_val), Type::Bool)
211            }
212            swamp_script_ast::LiteralKind::EnumVariant(enum_literal) => {
213                let (enum_name, variant_name) = match enum_literal {
214                    swamp_script_ast::EnumVariantLiteral::Simple(enum_name, variant_name) => {
215                        (enum_name, variant_name)
216                    }
217                    swamp_script_ast::EnumVariantLiteral::Tuple(enum_name, variant_name, _) => {
218                        (enum_name, variant_name)
219                    }
220                    swamp_script_ast::EnumVariantLiteral::Struct(enum_name, variant_name, _, _) => {
221                        (enum_name, variant_name)
222                    }
223                };
224
225                let (symbol_table, name) = self.get_symbol_table_and_name(enum_name)?;
226                if let Some(enum_type_ref) = symbol_table.get_enum(&name) {
227                    let enum_type_clone = enum_type_ref.clone();
228                    let enum_type = Type::Enum(enum_type_ref.clone());
229
230                    // Handle enum variant literals in patterns
231                    let variant_ref = self.analyze_enum_variant_ref(enum_name, variant_name)?;
232
233                    let resolved_data = match enum_literal {
234                        swamp_script_ast::EnumVariantLiteral::Simple(_, _) => {
235                            EnumLiteralData::Nothing
236                        }
237                        swamp_script_ast::EnumVariantLiteral::Tuple(
238                            _node,
239                            _variant,
240                            expressions,
241                        ) => {
242                            let resolved = self.analyze_argument_expressions(None, expressions)?;
243                            EnumLiteralData::Tuple(resolved)
244                        }
245                        swamp_script_ast::EnumVariantLiteral::Struct(
246                            _qualified_type_identifier,
247                            variant,
248                            anonym_struct_field_and_expressions,
249                            detected_rest,
250                        ) => {
251                            if let EnumVariantType::Struct(ref resolved_variant_struct_ref) =
252                                variant_ref
253                            {
254                                if anonym_struct_field_and_expressions.len()
255                                    != resolved_variant_struct_ref
256                                        .anon_struct
257                                        .field_name_sorted_fields
258                                        .len()
259                                {
260                                    return Err(self.create_err(
261                                        ErrorKind::WrongNumberOfArguments(
262                                            anonym_struct_field_and_expressions.len(),
263                                            resolved_variant_struct_ref
264                                                .anon_struct
265                                                .field_name_sorted_fields
266                                                .len(),
267                                        ),
268                                        &variant.0,
269                                    ));
270                                }
271
272                                let resolved = self.analyze_anon_struct_instantiation(
273                                    &variant.0.clone(),
274                                    &resolved_variant_struct_ref.anon_struct,
275                                    anonym_struct_field_and_expressions,
276                                    *detected_rest,
277                                )?;
278
279                                EnumLiteralData::Struct(resolved)
280                            } else {
281                                return Err(self.create_err(
282                                    ErrorKind::WrongEnumVariantContainer(variant_ref.clone()),
283                                    &variant.0,
284                                ));
285                            }
286                        }
287                    };
288
289                    return Ok((
290                        Literal::EnumVariantLiteral(enum_type_clone, variant_ref, resolved_data),
291                        enum_type,
292                    ));
293                }
294                return Err(self.create_err(ErrorKind::UnknownEnumType, ast_node));
295            }
296
297            swamp_script_ast::LiteralKind::Tuple(expressions) => {
298                let (tuple_type_ref, resolved_items) = self.analyze_tuple_literal(expressions)?;
299                (
300                    Literal::TupleLiteral(tuple_type_ref.clone(), resolved_items),
301                    Type::Tuple(tuple_type_ref),
302                )
303            }
304            swamp_script_ast::LiteralKind::None => {
305                if let Some(found_expected_type) = context.expected_type {
306                    if let Type::Optional(_some_type) = found_expected_type {
307                        return Ok((Literal::NoneLiteral, found_expected_type.clone()));
308                    }
309                }
310                return Err(self.create_err(ErrorKind::NoneNeedsExpectedTypeHint, &ast_node));
311            }
312            &&swamp_script_ast::LiteralKind::Slice(_)
313            | &swamp_script_ast::LiteralKind::SlicePair(_) => todo!(),
314        };
315
316        Ok(resolved_literal)
317    }
318
319    fn analyze_tuple_literal(
320        &mut self,
321        items: &[swamp_script_ast::Expression],
322    ) -> Result<(Vec<Type>, Vec<Expression>), Error> {
323        let expressions = self.analyze_argument_expressions(None, items)?;
324        let mut tuple_types = Vec::new();
325        for expr in &expressions {
326            let item_type = expr.ty.clone();
327            tuple_types.push(item_type);
328        }
329
330        Ok((tuple_types, expressions))
331    }
332
333    fn analyze_slice_pair_literal(
334        &mut self,
335        node: &swamp_script_ast::Node,
336        entries: &[(swamp_script_ast::Expression, swamp_script_ast::Expression)],
337    ) -> Result<(Vec<(Expression, Expression)>, Type, Type), Error> {
338        if entries.is_empty() {
339            return Ok((vec![], Type::Unit, Type::Unit));
340        }
341
342        // Resolve first entry to determine map types
343        let (first_key, first_value) = &entries[0];
344        let anything_context = TypeContext::new_anything_argument();
345        let resolved_first_key = self.analyze_expression(first_key, &anything_context)?;
346        let resolved_first_value = self.analyze_expression(first_value, &anything_context)?;
347        let key_type = resolved_first_key.ty.clone();
348        let value_type = resolved_first_value.ty.clone();
349
350        let key_context = TypeContext::new_argument(&key_type);
351        let value_context = TypeContext::new_argument(&value_type);
352
353        // Check all entries match the types
354        let mut resolved_entries = Vec::new();
355        resolved_entries.push((resolved_first_key, resolved_first_value));
356
357        for (key, value) in entries.iter().skip(1) {
358            let resolved_key = self.analyze_expression(key, &key_context)?;
359            let resolved_value = self.analyze_expression(value, &value_context)?;
360
361            if !resolved_key.ty.compatible_with(&key_type) {
362                return Err(self.create_err(
363                    ErrorKind::MapKeyTypeMismatch {
364                        expected: key_type,
365                        found: resolved_key.ty,
366                    },
367                    node,
368                ));
369            }
370
371            if !resolved_value.ty.compatible_with(&value_type) {
372                return Err(self.create_err(
373                    ErrorKind::MapValueTypeMismatch {
374                        expected: value_type,
375                        found: resolved_value.ty,
376                    },
377                    node,
378                ));
379            }
380
381            resolved_entries.push((resolved_key, resolved_value));
382        }
383
384        Ok((resolved_entries, key_type, value_type))
385    }
386
387    #[must_use]
388    pub fn create_err(&self, kind: ErrorKind, ast_node: &swamp_script_ast::Node) -> Error {
389        error!(?kind, "error created");
390        Error {
391            node: self.to_node(ast_node),
392            kind,
393        }
394    }
395
396    #[must_use]
397    pub fn create_err_resolved(&self, kind: ErrorKind, resolved_node: &Node) -> Error {
398        Error {
399            node: resolved_node.clone(),
400            kind,
401        }
402    }
403}