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