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<'a> Analyzer<'a> {
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.anon_struct.defined_fields.len()
95                                {
96                                    return Err(self.create_err(
97                                        ErrorKind::WrongNumberOfArguments(
98                                            anonym_struct_field_and_expressions.len(),
99                                            resolved_variant_struct_ref
100                                                .anon_struct
101                                                .defined_fields
102                                                .len(),
103                                        ),
104                                        &variant.0,
105                                    ));
106                                }
107
108                                let resolved = self.analyze_anon_struct_instantiation(
109                                    &variant.0.clone(),
110                                    &resolved_variant_struct_ref.anon_struct,
111                                    anonym_struct_field_and_expressions,
112                                    false,
113                                )?;
114
115                                EnumLiteralData::Struct(resolved)
116                            } else {
117                                return Err(self.create_err(
118                                    ErrorKind::WrongEnumVariantContainer(variant_ref.clone()),
119                                    &variant.0,
120                                ));
121                            }
122                        }
123                    };
124
125                    return Ok((
126                        Literal::EnumVariantLiteral(variant_ref, resolved_data),
127                        enum_type,
128                    ));
129                }
130                return Err(self.create_err(ErrorKind::UnknownEnumType, ast_node));
131            }
132
133            swamp_script_ast::LiteralKind::Array(items) => {
134                if items.len() == 0 {
135                    if let Some(found_expected_type) = context.expected_type {
136                        match found_expected_type {
137                            Type::Map(map_type_ref) => (
138                                Literal::Map(map_type_ref.clone(), vec![]),
139                                found_expected_type.clone(),
140                            ),
141                            Type::Array(array_type_ref) => (
142                                Literal::Array(array_type_ref.clone(), vec![]),
143                                found_expected_type.clone(),
144                            ),
145                            _ => {
146                                return Err(self.create_err(
147                                    ErrorKind::EmptyArrayCanOnlyBeMapOrArray,
148                                    &ast_node,
149                                ));
150                            }
151                        }
152                    } else {
153                        return Err(
154                            self.create_err(ErrorKind::EmptyArrayCanOnlyBeMapOrArray, ast_node)
155                        );
156                    }
157                } else {
158                    let (array_type_ref, resolved_items) =
159                        self.analyze_array_type_helper(ast_node, items, context.expected_type)?;
160                    (
161                        Literal::Array(array_type_ref.clone(), resolved_items),
162                        Type::Array(array_type_ref),
163                    )
164                }
165            }
166
167            swamp_script_ast::LiteralKind::Map(entries) => {
168                let (map_literal, map_type_ref) = self.analyze_map_literal(ast_node, &entries)?;
169
170                (map_literal, Type::Map(map_type_ref.clone()))
171            }
172
173            swamp_script_ast::LiteralKind::Tuple(expressions) => {
174                let (tuple_type_ref, resolved_items) = self.analyze_tuple_literal(&expressions)?;
175                (
176                    Literal::TupleLiteral(tuple_type_ref.clone(), resolved_items),
177                    Type::Tuple(tuple_type_ref.clone()),
178                )
179            }
180            swamp_script_ast::LiteralKind::None => {
181                if let Some(found_expected_type) = context.expected_type {
182                    if let Type::Optional(_some_type) = found_expected_type {
183                        return Ok((Literal::NoneLiteral, found_expected_type.clone()));
184                    }
185                }
186                return Err(self.create_err(ErrorKind::NoneNeedsExpectedTypeHint, &ast_node));
187            }
188        };
189
190        Ok(resolved_literal)
191    }
192
193    fn analyze_tuple_literal(
194        &mut self,
195        items: &[swamp_script_ast::Expression],
196    ) -> Result<(TupleTypeRef, Vec<Expression>), Error> {
197        let expressions = self.analyze_argument_expressions(None, items)?;
198        let mut tuple_types = Vec::new();
199        for expr in &expressions {
200            let item_type = expr.ty.clone();
201            tuple_types.push(item_type);
202        }
203
204        let tuple_type = TupleType(tuple_types);
205
206        let tuple_type_ref = Rc::new(tuple_type);
207
208        Ok((tuple_type_ref, expressions))
209    }
210
211    fn analyze_map_literal(
212        &mut self,
213        node: &swamp_script_ast::Node,
214        entries: &[(swamp_script_ast::Expression, swamp_script_ast::Expression)],
215    ) -> Result<(Literal, MapTypeRef), Error> {
216        if entries.is_empty() {
217            return Err(self.create_err(ErrorKind::EmptyMapLiteral, node));
218        }
219
220        // Resolve first entry to determine map types
221        let (first_key, first_value) = &entries[0];
222        let anything_context = TypeContext::new_anything_argument();
223        let resolved_first_key = self.analyze_expression(first_key, &anything_context)?;
224        let resolved_first_value = self.analyze_expression(first_value, &anything_context)?;
225        let key_type = resolved_first_key.ty.clone();
226        let value_type = resolved_first_value.ty.clone();
227
228        let key_context = TypeContext::new_argument(&key_type);
229        let value_context = TypeContext::new_argument(&value_type);
230
231        // Check all entries match the types
232        let mut resolved_entries = Vec::new();
233        resolved_entries.push((resolved_first_key, resolved_first_value));
234
235        for (key, value) in entries.iter().skip(1) {
236            let resolved_key = self.analyze_expression(key, &key_context)?;
237            let resolved_value = self.analyze_expression(value, &value_context)?;
238
239            if !resolved_key.ty.compatible_with(&key_type) {
240                return Err(self.create_err(
241                    ErrorKind::MapKeyTypeMismatch {
242                        expected: key_type,
243                        found: resolved_key.ty.clone(),
244                    },
245                    node,
246                ));
247            }
248
249            if !resolved_value.ty.compatible_with(&value_type) {
250                return Err(self.create_err(
251                    ErrorKind::MapValueTypeMismatch {
252                        expected: value_type,
253                        found: resolved_value.ty.clone(),
254                    },
255                    node,
256                ));
257            }
258
259            resolved_entries.push((resolved_key, resolved_value));
260        }
261
262        let resolved_map_type = MapType {
263            key_type,
264            value_type,
265        };
266
267        let resolved_map_type_ref = Rc::new(resolved_map_type);
268
269        let literal = Literal::Map(resolved_map_type_ref.clone(), resolved_entries);
270        Ok((literal, resolved_map_type_ref))
271    }
272
273    #[must_use]
274    pub fn create_err(&self, kind: ErrorKind, ast_node: &swamp_script_ast::Node) -> Error {
275        error!(?kind, "error created");
276        Error {
277            node: self.to_node(ast_node),
278            kind,
279        }
280    }
281
282    #[must_use]
283    pub fn create_err_resolved(&self, kind: ErrorKind, resolved_node: &Node) -> Error {
284        Error {
285            node: resolved_node.clone(),
286            kind,
287        }
288    }
289}