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