swamp_analyzer/
literal.rs

1/*
2 * Copyright (c) Peter Bjorklund. All rights reserved. https://github.com/swamp/swamp
3 * Licensed under the MIT License. See LICENSE in the project root for license information.
4 */
5use crate::{Analyzer, TypeContext};
6use source_map_node::Node;
7use std::env::current_dir;
8use swamp_semantic::err::ErrorKind;
9use swamp_semantic::prelude::Error;
10use swamp_semantic::{EnumLiteralExpressions, ExpressionKind};
11use swamp_semantic::{Expression, Fp};
12use swamp_types::prelude::*;
13use tracing::{error, warn};
14
15impl Analyzer<'_> {
16    /// # Errors
17    ///
18    /// # Panics
19    /// if core hasn't added `Vec`
20    #[allow(clippy::too_many_lines)]
21    pub fn analyze_complex_literal_to_expression(
22        &mut self,
23        ast_expression: &swamp_ast::Expression,
24        ast_literal_kind: &swamp_ast::LiteralKind,
25        parent_context: &TypeContext,
26    ) -> Expression {
27        // We intentionally take the inner optional type if it exists
28        // Since we know that the caller will eventually wrap this with an
29        // ExpressionKind::Option()
30        let literal_context = parent_context.expected_type_or_optional_inner();
31
32        let ast_node = &ast_expression.node;
33        let (lit_kind, literal_type) = match &ast_literal_kind {
34            swamp_ast::LiteralKind::InternalInitializerList(items) => {
35                let (collection_type, resolved_items) =
36                    self.analyze_internal_initializer_list(ast_node, items, &literal_context);
37
38                (
39                    ExpressionKind::InitializerList(collection_type.clone(), resolved_items),
40                    collection_type,
41                )
42            }
43
44            swamp_ast::LiteralKind::InternalInitializerPairList(entries) => {
45                let (collection_type, resolved_items) = self
46                    .analyze_internal_initializer_pair_list(ast_node, entries, &literal_context);
47
48                (
49                    ExpressionKind::InitializerPairList(collection_type.clone(), resolved_items),
50                    collection_type,
51                )
52            }
53
54            _ => {
55                return self.analyze_literal(
56                    ast_node,
57                    ast_literal_kind,
58                    parent_context,
59                    &literal_context,
60                );
61            }
62        };
63
64        self.create_expr(lit_kind, literal_type, ast_node)
65    }
66
67    #[allow(clippy::too_many_lines)]
68    pub(crate) fn analyze_literal(
69        &mut self,
70        ast_node: &swamp_ast::Node,
71        ast_literal_kind: &swamp_ast::LiteralKind,
72        parent_context: &TypeContext,
73        context: &TypeContext,
74    ) -> Expression {
75        let node_text = self.get_text(ast_node);
76        let (expression_kind, ty) = match &ast_literal_kind {
77            swamp_ast::LiteralKind::Int => match Self::str_to_int(node_text) {
78                Err(int_err) => {
79                    return self.create_err(ErrorKind::IntConversionError(int_err), ast_node);
80                }
81                Ok(int_value) => (
82                    ExpressionKind::IntLiteral(int_value),
83                    self.shared.state.types.int(),
84                ),
85            },
86            swamp_ast::LiteralKind::Float => match Self::str_to_float(node_text) {
87                Err(float_err) => {
88                    return self.create_err(ErrorKind::FloatConversionError(float_err), ast_node);
89                }
90                Ok(float_value) => (
91                    ExpressionKind::FloatLiteral(Fp::from(float_value)),
92                    self.shared.state.types.float(),
93                ),
94            },
95            swamp_ast::LiteralKind::String(processed_string) => (
96                ExpressionKind::StringLiteral(processed_string.to_string()),
97                self.shared.state.types.string(),
98            ),
99            swamp_ast::LiteralKind::Bool => match Self::str_to_bool(node_text) {
100                Err(_bool_err) => return self.create_err(ErrorKind::BoolConversionError, ast_node),
101                Ok(bool_value) => (
102                    ExpressionKind::BoolLiteral(bool_value),
103                    self.shared.state.types.bool(),
104                ),
105            },
106            swamp_ast::LiteralKind::EnumVariant(enum_literal) => {
107                let (enum_name, variant_name_node) = match enum_literal {
108                    swamp_ast::EnumVariantLiteral::Simple(enum_name, variant_name) => {
109                        (enum_name, variant_name)
110                    }
111                    swamp_ast::EnumVariantLiteral::Tuple(enum_name, variant_name, _) => {
112                        (enum_name, variant_name)
113                    }
114                    swamp_ast::EnumVariantLiteral::Struct(enum_name, variant_name, _, _) => {
115                        (enum_name, variant_name)
116                    }
117                };
118
119                // Get the text first to avoid borrowing conflicts
120                let variant_name_text = self.get_text(&variant_name_node.0).to_string();
121
122                // Get the enum type, then release the borrow
123                let found_enum_type = {
124                    let Some((symbol_table, name)) = self.get_symbol_table_and_name(enum_name)
125                    else {
126                        self.add_err(ErrorKind::UnknownModule, &enum_name.name.0);
127                        return self.create_err(ErrorKind::UnknownEnumVariantType, ast_node);
128                    };
129                    let Some(found_enum_type) = symbol_table.get_type(&name) else {
130                        return self.create_err(ErrorKind::UnknownEnumType, ast_node);
131                    };
132                    found_enum_type.clone()
133                };
134
135                let TypeKind::Enum(enum_type) = &*found_enum_type.kind else {
136                    return self.create_err(ErrorKind::UnknownEnumType, ast_node);
137                };
138                let variant_name = &variant_name_text;
139                // Handle enum variant literals in patterns
140                let Some(variant_ref) = enum_type.get_variant(variant_name) else {
141                    return self
142                        .create_err(ErrorKind::UnknownEnumVariantType, &variant_name_node.0);
143                };
144
145                let resolved_data = match enum_literal {
146                    swamp_ast::EnumVariantLiteral::Simple(_, _) => EnumLiteralExpressions::Nothing,
147                    swamp_ast::EnumVariantLiteral::Tuple(_node, _variant, ast_expressions) => {
148                        if let TypeKind::Tuple(tuple_field_types) = &*variant_ref.payload_type.kind
149                        {
150                            // Multi-element tuple variant
151                            if tuple_field_types.len() != ast_expressions.len() {
152                                return self.create_err(
153                                    ErrorKind::WrongNumberOfArguments(
154                                        tuple_field_types.len(),
155                                        ast_expressions.len(),
156                                    ),
157                                    ast_node,
158                                );
159                            }
160
161                            let resolved_expression = tuple_field_types
162                                .iter()
163                                .zip(ast_expressions)
164                                .map(|(expected_type, ast_expression)| {
165                                    let ctx = context.argument(expected_type);
166                                    self.analyze_expression(ast_expression, &ctx)
167                                })
168                                .collect();
169
170                            EnumLiteralExpressions::Tuple(resolved_expression)
171                        } else {
172                            // Single-element variant with direct payload type
173                            if ast_expressions.len() != 1 {
174                                return self.create_err(
175                                    ErrorKind::WrongNumberOfArguments(1, ast_expressions.len()),
176                                    ast_node,
177                                );
178                            }
179
180                            let ctx = context.argument(&variant_ref.payload_type);
181                            let resolved_expression =
182                                self.analyze_expression(&ast_expressions[0], &ctx);
183
184                            EnumLiteralExpressions::Tuple(vec![resolved_expression])
185                        }
186                    }
187                    swamp_ast::EnumVariantLiteral::Struct(
188                        _qualified_type_identifier,
189                        variant,
190                        anonym_struct_field_and_expressions,
191                        detected_rest,
192                    ) => {
193                        let TypeKind::AnonymousStruct(anon_payload) =
194                            &*variant_ref.payload_type.kind
195                        else {
196                            return self.create_err(
197                                ErrorKind::WrongEnumVariantContainer(variant_ref.clone()),
198                                ast_node,
199                            );
200                        };
201
202                        if anonym_struct_field_and_expressions.len()
203                            != anon_payload.field_name_sorted_fields.len()
204                        {
205                            return self.create_err(
206                                ErrorKind::WrongNumberOfArguments(
207                                    anonym_struct_field_and_expressions.len(),
208                                    anon_payload.field_name_sorted_fields.len(),
209                                ),
210                                &variant.0,
211                            );
212                        }
213
214                        let resolved_fields = self.analyze_anon_struct_instantiation(
215                            &variant.0.clone(),
216                            anon_payload,
217                            anonym_struct_field_and_expressions,
218                            *detected_rest,
219                        );
220
221                        EnumLiteralExpressions::Struct(resolved_fields)
222                    }
223                };
224
225                (
226                    ExpressionKind::EnumVariantLiteral(variant_ref.clone(), resolved_data),
227                    found_enum_type.clone(),
228                )
229            }
230
231            swamp_ast::LiteralKind::Tuple(expressions) => {
232                let (tuple_type_ref, resolved_items) =
233                    self.analyze_tuple_literal(expressions, context);
234                let tuple_type = self.shared.state.types.tuple(tuple_type_ref);
235                (ExpressionKind::TupleLiteral(resolved_items), tuple_type)
236            }
237            swamp_ast::LiteralKind::None => {
238                if let Some(found_expected_type) = parent_context.expected_type {
239                    let underlying = found_expected_type;
240                    if let TypeKind::Optional(_some_type) = &*underlying.kind {
241                        (ExpressionKind::NoneLiteral, underlying.clone())
242                    } else {
243                        return self.create_err(ErrorKind::NoneNeedsExpectedTypeHint, ast_node);
244                    }
245                } else {
246                    return self.create_err(ErrorKind::NoneNeedsExpectedTypeHint, ast_node);
247                }
248            }
249            &&swamp_ast::LiteralKind::InternalInitializerList(_)
250            | &swamp_ast::LiteralKind::InternalInitializerPairList(_) => {
251                panic!("initializer lists are not basic literals")
252            }
253        };
254
255        self.create_expr(expression_kind, ty, ast_node)
256    }
257
258    fn analyze_tuple_literal(
259        &mut self,
260        items: &[swamp_ast::Expression],
261        context: &TypeContext,
262    ) -> (Vec<TypeRef>, Vec<Expression>) {
263        let expressions = self.analyze_argument_expressions(None, context, items);
264        let mut tuple_types = Vec::new();
265        for expr in &expressions {
266            let item_type = expr.ty.clone();
267            tuple_types.push(item_type);
268        }
269
270        (tuple_types, expressions)
271    }
272
273    fn analyze_tuple_type(
274        &mut self,
275        node: &swamp_ast::Node,
276        expected_types: &[TypeRef],
277        ast_expressions: &Vec<swamp_ast::Expression>,
278    ) -> Vec<Expression> {
279        if ast_expressions.len() != expected_types.len() {
280            return vec![self.create_err(
281                ErrorKind::WrongNumberOfArguments(expected_types.len(), ast_expressions.len()),
282                node,
283            )];
284        }
285
286        let mut expressions = Vec::new();
287        for (expected_type, expr) in expected_types.iter().zip(ast_expressions) {
288            let context = TypeContext::new_argument(
289                expected_type,
290                expected_type.collection_view_that_needs_explicit_storage(),
291            );
292            let resolved_expr = self.analyze_expression(expr, &context);
293            expressions.push(resolved_expr);
294        }
295
296        expressions
297    }
298
299    pub fn add_err(&mut self, kind: ErrorKind, ast_node: &swamp_ast::Node) {
300        self.add_err_resolved(kind, &self.to_node(ast_node));
301    }
302    pub(crate) fn add_hint(&mut self, kind: ErrorKind, ast_node: &swamp_ast::Node) {
303        self.add_hint_resolved(kind, &self.to_node(ast_node));
304    }
305
306    pub(crate) fn add_hint_resolved(&mut self, kind: ErrorKind, node: &Node) {
307        warn!(?kind, "add error");
308        let err = Error {
309            node: node.clone(),
310            kind,
311        };
312        let line_info = self
313            .shared
314            .source_map
315            .get_line(&node.span, &current_dir().unwrap());
316
317        eprintln!("{}:{} {}", line_info.row, line_info.col, line_info.line);
318        self.shared.state.hints.push(err);
319    }
320
321    pub(crate) fn add_err_resolved(&mut self, kind: ErrorKind, node: &Node) {
322        error!(?kind, "add error");
323        let err = Error {
324            node: node.clone(),
325            kind,
326        };
327        let line_info = self
328            .shared
329            .source_map
330            .get_line(&node.span, &current_dir().unwrap());
331
332        eprintln!("{}:{} {}", line_info.row, line_info.col, line_info.line);
333        self.shared.state.errors.push(err);
334    }
335
336    #[must_use]
337    pub fn create_err_vec(
338        &mut self,
339        kind: ErrorKind,
340        ast_node: &swamp_ast::Node,
341    ) -> Vec<Expression> {
342        vec![self.create_err(kind, ast_node)]
343    }
344
345    #[must_use]
346    pub fn create_err(&mut self, kind: ErrorKind, ast_node: &swamp_ast::Node) -> Expression {
347        self.add_err(kind.clone(), ast_node);
348
349        Expression {
350            ty: self.types().unit(),
351            node: self.to_node(ast_node),
352            kind: ExpressionKind::Error(kind),
353        }
354    }
355    #[must_use]
356    pub fn create_err_resolved(&mut self, kind: ErrorKind, resolved_node: &Node) -> Expression {
357        self.add_err_resolved(kind.clone(), resolved_node);
358
359        Expression {
360            ty: self.types().unit(),
361            node: resolved_node.clone(),
362            kind: ExpressionKind::Error(kind),
363        }
364    }
365}