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        if !actual_constant_type.can_be_stored_in_transient_field() {
48            self.add_err(ErrorKind::NeedStorage, &constant.constant_identifier.0);
49            return;
50        }
51        if !actual_constant_type.can_be_stored_in_field() {
52            self.add_hint(ErrorKind::NeedStorage, &constant.constant_identifier.0);
53        }
54
55        // TODO: investigate why FixedSizeArray gets converted to InitializerList
56
57        let name_node = self.to_node(&constant.constant_identifier.0);
58        let name_text = self.get_text_resolved(&name_node).to_string();
59        let constant = Constant {
60            name: name_node.clone(),
61            assigned_name: name_text,
62            id: ConstantId::from(self.shared.state.internal_function_id_allocator.alloc()),
63            expr: resolved_expr,
64            resolved_type: actual_constant_type,
65            function_scope_state: self.scope.total_scopes.clone(),
66        };
67
68        let const_ref = match self.shared.definition_table.add_constant(constant) {
69            Ok(c) => c,
70            Err(sem_err) => {
71                self.add_err_resolved(ErrorKind::SemanticError(sem_err), &name_node);
72                return;
73            }
74        };
75
76        match self
77            .shared
78            .lookup_table
79            .add_constant_link(const_ref.clone())
80        {
81            Ok(c) => c,
82            Err(sem_err) => {
83                self.add_err_resolved(ErrorKind::SemanticError(sem_err), &name_node);
84                return;
85            }
86        }
87
88        // This extra storage of the constants in modules is to have them in analyze / dependency order
89        self.shared
90            .state
91            .constants_in_dependency_order
92            .push(const_ref);
93    }
94
95    pub(crate) fn analyze_constant_definition(&mut self, constant: &swamp_ast::ConstantInfo) {
96        self.analyze_constant(constant);
97    }
98
99    pub(crate) fn analyze_constant_access(
100        &mut self,
101        qualified_constant_identifier: &swamp_ast::QualifiedConstantIdentifier,
102    ) -> Expression {
103        match self.try_find_constant(qualified_constant_identifier) {
104            None => self.create_err(
105                ErrorKind::UnknownConstant,
106                &qualified_constant_identifier.name,
107            ),
108            Some(constant_ref) => {
109                let ty = constant_ref.resolved_type.clone();
110                self.create_expr(
111                    ExpressionKind::ConstantAccess(constant_ref.clone()),
112                    ty,
113                    &qualified_constant_identifier.name,
114                )
115            }
116        }
117    }
118
119    #[must_use]
120    pub fn try_find_constant(
121        &self,
122        qualified_constant_identifier: &swamp_ast::QualifiedConstantIdentifier,
123    ) -> Option<&ConstantRef> {
124        let path = self.get_module_path(qualified_constant_identifier.module_path.as_ref());
125        let constant_name = self.get_text(&qualified_constant_identifier.name);
126
127        let maybe_symbol_table = self.shared.get_symbol_table(&path);
128        maybe_symbol_table.map_or_else(
129            || None,
130            |symbol_table| Some(symbol_table.get_constant(constant_name)),
131        )?
132    }
133}