swamp_analyzer/
constant.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 swamp_semantic::err::ErrorKind;
7use swamp_semantic::{Constant, ConstantId, ConstantRef, Expression, ExpressionKind};
8
9impl Analyzer<'_> {
10    fn analyze_constant(&mut self, constant: &swamp_ast::ConstantInfo) {
11        let maybe_annotation_type = constant
12            .annotation
13            .as_ref()
14            .map(|found_ast_type| self.analyze_type(found_ast_type));
15
16        let context = TypeContext::new_unsure_argument(maybe_annotation_type.as_ref(), true);
17
18        let resolved_expr = self.analyze_expression(&constant.expression, &context);
19
20        let actual_constant_type = if let Some(annotation_type) = maybe_annotation_type {
21            let extra_verification = false;
22            if extra_verification {
23                let debug_context = TypeContext::new_anything_argument(
24                    annotation_type.collection_view_that_needs_explicit_storage(),
25                );
26                let worked_without_annotation =
27                    self.analyze_expression(&constant.expression, &debug_context);
28                if self
29                    .shared
30                    .state
31                    .types
32                    .compatible_with(&annotation_type, &worked_without_annotation.ty)
33                {
34                    let identifier_name = { self.get_text(&constant.constant_identifier.0) };
35                    eprintln!(
36                        "annotation was not needed for constant: {identifier_name} in {:?}",
37                        self.module_path
38                    );
39                }
40            }
41            annotation_type
42        } else {
43            resolved_expr.ty.clone()
44        };
45
46        // TODO: do not use identifier_name except for asserts
47        let identifier_name = { self.get_text(&constant.constant_identifier.0) };
48        debug_assert!(
49            actual_constant_type.can_be_stored_in_field(),
50            "this field is not blittable {identifier_name:?}"
51        ); // TODO: investigate why FixedSizeArray gets converted to InitializerList
52
53        let name_node = self.to_node(&constant.constant_identifier.0);
54        let name_text = self.get_text_resolved(&name_node).to_string();
55        let constant = Constant {
56            name: name_node.clone(),
57            assigned_name: name_text,
58            id: ConstantId::from(self.shared.state.internal_function_id_allocator.alloc()),
59            expr: resolved_expr,
60            resolved_type: actual_constant_type,
61            function_scope_state: self.scope.total_scopes.clone(),
62        };
63
64        let const_ref = match self.shared.definition_table.add_constant(constant) {
65            Ok(c) => c,
66            Err(sem_err) => {
67                self.add_err_resolved(ErrorKind::SemanticError(sem_err), &name_node);
68                return;
69            }
70        };
71
72        match self
73            .shared
74            .lookup_table
75            .add_constant_link(const_ref.clone())
76        {
77            Ok(c) => c,
78            Err(sem_err) => {
79                self.add_err_resolved(ErrorKind::SemanticError(sem_err), &name_node);
80                return;
81            }
82        }
83
84        // This extra storage of the constants in modules is to have them in analyze / dependency order
85        self.shared
86            .state
87            .constants_in_dependency_order
88            .push(const_ref);
89    }
90
91    pub(crate) fn analyze_constant_definition(&mut self, constant: &swamp_ast::ConstantInfo) {
92        self.analyze_constant(constant);
93    }
94
95    pub(crate) fn analyze_constant_access(
96        &mut self,
97        qualified_constant_identifier: &swamp_ast::QualifiedConstantIdentifier,
98    ) -> Expression {
99        match self.try_find_constant(qualified_constant_identifier) {
100            None => self.create_err(
101                ErrorKind::UnknownConstant,
102                &qualified_constant_identifier.name,
103            ),
104            Some(constant_ref) => {
105                let ty = constant_ref.resolved_type.clone();
106                self.create_expr(
107                    ExpressionKind::ConstantAccess(constant_ref.clone()),
108                    ty,
109                    &qualified_constant_identifier.name,
110                )
111            }
112        }
113    }
114
115    #[must_use]
116    pub fn try_find_constant(
117        &self,
118        qualified_constant_identifier: &swamp_ast::QualifiedConstantIdentifier,
119    ) -> Option<&ConstantRef> {
120        let path = self.get_module_path(qualified_constant_identifier.module_path.as_ref());
121        let constant_name = self.get_text(&qualified_constant_identifier.name);
122
123        let maybe_symbol_table = self.shared.get_symbol_table(&path);
124        maybe_symbol_table.map_or_else(
125            || None,
126            |symbol_table| Some(symbol_table.get_constant(constant_name)),
127        )?
128    }
129}