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