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 std::rc::Rc;
8use swamp_script_semantic::{
9    EnumLiteralData, EnumVariantType, Expression, Fp, Literal, MapType, MapTypeRef, Node,
10    TupleType, TupleTypeRef, Type,
11};
12use tracing::error;
13
14impl Analyzer<'_> {
15    #[allow(clippy::too_many_lines)]
16    pub(crate) fn analyze_literal(
17        &mut self,
18        ast_node: &swamp_script_ast::Node,
19        ast_literal_kind: &swamp_script_ast::LiteralKind,
20        context: &TypeContext,
21    ) -> Result<(Literal, Type), Error> {
22        let node_text = self.get_text(ast_node);
23        let resolved_literal = match &ast_literal_kind {
24            swamp_script_ast::LiteralKind::Int => (
25                Literal::IntLiteral(Self::str_to_int(node_text).map_err(|int_conversion_err| {
26                    self.create_err(ErrorKind::IntConversionError(int_conversion_err), ast_node)
27                })?),
28                Type::Int,
29            ),
30            swamp_script_ast::LiteralKind::Float => {
31                let float = Self::str_to_float(node_text).map_err(|float_conversion_err| {
32                    self.create_err(
33                        ErrorKind::FloatConversionError(float_conversion_err),
34                        ast_node,
35                    )
36                })?;
37                (Literal::FloatLiteral(Fp::from(float)), Type::Float)
38            }
39            swamp_script_ast::LiteralKind::String(processed_string) => (
40                Literal::StringLiteral(processed_string.to_string()),
41                Type::String,
42            ),
43            swamp_script_ast::LiteralKind::Bool => {
44                let bool_val = if node_text == "false" {
45                    false
46                } else if node_text == "true" {
47                    true
48                } else {
49                    return Err(self.create_err(ErrorKind::BoolConversionError, ast_node));
50                };
51                (Literal::BoolLiteral(bool_val), Type::Bool)
52            }
53            swamp_script_ast::LiteralKind::EnumVariant(enum_literal) => {
54                let (enum_name, variant_name) = match enum_literal {
55                    swamp_script_ast::EnumVariantLiteral::Simple(enum_name, variant_name) => {
56                        (enum_name, variant_name)
57                    }
58                    swamp_script_ast::EnumVariantLiteral::Tuple(enum_name, variant_name, _) => {
59                        (enum_name, variant_name)
60                    }
61                    swamp_script_ast::EnumVariantLiteral::Struct(enum_name, variant_name, _) => {
62                        (enum_name, variant_name)
63                    }
64                };
65
66                let (symbol_table, name) = self.get_symbol_table_and_name(enum_name)?;
67                if let Some(enum_type_ref) = symbol_table.get_enum(&name) {
68                    let enum_type = Type::Enum(enum_type_ref.clone());
69
70                    // Handle enum variant literals in patterns
71                    let variant_ref = self.analyze_enum_variant_ref(enum_name, variant_name)?;
72
73                    let resolved_data = match enum_literal {
74                        swamp_script_ast::EnumVariantLiteral::Simple(_, _) => {
75                            EnumLiteralData::Nothing
76                        }
77                        swamp_script_ast::EnumVariantLiteral::Tuple(
78                            _node,
79                            _variant,
80                            expressions,
81                        ) => {
82                            let resolved = self.analyze_argument_expressions(None, expressions)?;
83                            EnumLiteralData::Tuple(resolved)
84                        }
85                        swamp_script_ast::EnumVariantLiteral::Struct(
86                            _qualified_type_identifier,
87                            variant,
88                            anonym_struct_field_and_expressions,
89                        ) => {
90                            if let EnumVariantType::Struct(resolved_variant_struct_ref) =
91                                &*variant_ref
92                            {
93                                if anonym_struct_field_and_expressions.len()
94                                    != resolved_variant_struct_ref
95                                        .anon_struct
96                                        .field_name_sorted_fields
97                                        .len()
98                                {
99                                    return Err(self.create_err(
100                                        ErrorKind::WrongNumberOfArguments(
101                                            anonym_struct_field_and_expressions.len(),
102                                            resolved_variant_struct_ref
103                                                .anon_struct
104                                                .field_name_sorted_fields
105                                                .len(),
106                                        ),
107                                        &variant.0,
108                                    ));
109                                }
110
111                                let resolved = self.analyze_anon_struct_instantiation(
112                                    &variant.0.clone(),
113                                    &resolved_variant_struct_ref.anon_struct,
114                                    anonym_struct_field_and_expressions,
115                                    false,
116                                )?;
117
118                                EnumLiteralData::Struct(resolved)
119                            } else {
120                                return Err(self.create_err(
121                                    ErrorKind::WrongEnumVariantContainer(variant_ref.clone()),
122                                    &variant.0,
123                                ));
124                            }
125                        }
126                    };
127
128                    return Ok((
129                        Literal::EnumVariantLiteral(variant_ref, resolved_data),
130                        enum_type,
131                    ));
132                }
133                return Err(self.create_err(ErrorKind::UnknownEnumType, ast_node));
134            }
135
136            swamp_script_ast::LiteralKind::Array(items) => {
137                if items.len() == 0 {
138                    if let Some(found_expected_type) = context.expected_type {
139                        match found_expected_type {
140                            Type::Map(map_type_ref) => (
141                                Literal::Map(map_type_ref.clone(), vec![]),
142                                found_expected_type.clone(),
143                            ),
144                            Type::Array(array_type_ref) => (
145                                Literal::Array(array_type_ref.clone(), vec![]),
146                                found_expected_type.clone(),
147                            ),
148                            _ => {
149                                return Err(self.create_err(
150                                    ErrorKind::EmptyArrayCanOnlyBeMapOrArray,
151                                    ast_node,
152                                ));
153                            }
154                        }
155                    } else {
156                        return Err(
157                            self.create_err(ErrorKind::EmptyArrayCanOnlyBeMapOrArray, ast_node)
158                        );
159                    }
160                } else {
161                    let (array_type_ref, resolved_items) =
162                        self.analyze_array_type_helper(ast_node, items, context.expected_type)?;
163                    (
164                        Literal::Array(array_type_ref.clone(), resolved_items),
165                        Type::Array(array_type_ref),
166                    )
167                }
168            }
169
170            swamp_script_ast::LiteralKind::Map(entries) => {
171                let (map_literal, map_type_ref) = self.analyze_map_literal(ast_node, &entries)?;
172
173                (map_literal, Type::Map(map_type_ref))
174            }
175
176            swamp_script_ast::LiteralKind::Tuple(expressions) => {
177                let (tuple_type_ref, resolved_items) = self.analyze_tuple_literal(&expressions)?;
178                (
179                    Literal::TupleLiteral(tuple_type_ref.clone(), resolved_items),
180                    Type::Tuple(tuple_type_ref),
181                )
182            }
183            swamp_script_ast::LiteralKind::None => {
184                if let Some(found_expected_type) = context.expected_type {
185                    if let Type::Optional(_some_type) = found_expected_type {
186                        return Ok((Literal::NoneLiteral, found_expected_type.clone()));
187                    }
188                }
189                return Err(self.create_err(ErrorKind::NoneNeedsExpectedTypeHint, &ast_node));
190            }
191        };
192
193        Ok(resolved_literal)
194    }
195
196    fn analyze_tuple_literal(
197        &mut self,
198        items: &[swamp_script_ast::Expression],
199    ) -> Result<(TupleTypeRef, Vec<Expression>), Error> {
200        let expressions = self.analyze_argument_expressions(None, items)?;
201        let mut tuple_types = Vec::new();
202        for expr in &expressions {
203            let item_type = expr.ty.clone();
204            tuple_types.push(item_type);
205        }
206
207        let tuple_type = TupleType(tuple_types);
208
209        let tuple_type_ref = Rc::new(tuple_type);
210
211        Ok((tuple_type_ref, expressions))
212    }
213
214    fn analyze_map_literal(
215        &mut self,
216        node: &swamp_script_ast::Node,
217        entries: &[(swamp_script_ast::Expression, swamp_script_ast::Expression)],
218    ) -> Result<(Literal, MapTypeRef), Error> {
219        if entries.is_empty() {
220            return Err(self.create_err(ErrorKind::EmptyMapLiteral, node));
221        }
222
223        // Resolve first entry to determine map types
224        let (first_key, first_value) = &entries[0];
225        let anything_context = TypeContext::new_anything_argument();
226        let resolved_first_key = self.analyze_expression(first_key, &anything_context)?;
227        let resolved_first_value = self.analyze_expression(first_value, &anything_context)?;
228        let key_type = resolved_first_key.ty.clone();
229        let value_type = resolved_first_value.ty.clone();
230
231        let key_context = TypeContext::new_argument(&key_type);
232        let value_context = TypeContext::new_argument(&value_type);
233
234        // Check all entries match the types
235        let mut resolved_entries = Vec::new();
236        resolved_entries.push((resolved_first_key, resolved_first_value));
237
238        for (key, value) in entries.iter().skip(1) {
239            let resolved_key = self.analyze_expression(key, &key_context)?;
240            let resolved_value = self.analyze_expression(value, &value_context)?;
241
242            if !resolved_key.ty.compatible_with(&key_type) {
243                return Err(self.create_err(
244                    ErrorKind::MapKeyTypeMismatch {
245                        expected: key_type,
246                        found: resolved_key.ty,
247                    },
248                    node,
249                ));
250            }
251
252            if !resolved_value.ty.compatible_with(&value_type) {
253                return Err(self.create_err(
254                    ErrorKind::MapValueTypeMismatch {
255                        expected: value_type,
256                        found: resolved_value.ty,
257                    },
258                    node,
259                ));
260            }
261
262            resolved_entries.push((resolved_key, resolved_value));
263        }
264
265        let resolved_map_type = MapType {
266            key_type,
267            value_type,
268        };
269
270        let resolved_map_type_ref = Rc::new(resolved_map_type);
271
272        let literal = Literal::Map(resolved_map_type_ref.clone(), resolved_entries);
273        Ok((literal, resolved_map_type_ref))
274    }
275
276    #[must_use]
277    pub fn create_err(&self, kind: ErrorKind, ast_node: &swamp_script_ast::Node) -> Error {
278        error!(?kind, "error created");
279        Error {
280            node: self.to_node(ast_node),
281            kind,
282        }
283    }
284
285    #[must_use]
286    pub fn create_err_resolved(&self, kind: ErrorKind, resolved_node: &Node) -> Error {
287        Error {
288            node: resolved_node.clone(),
289            kind,
290        }
291    }
292}