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