leo_passes/const_propagation/
visitor.rs

1// Copyright (C) 2019-2025 Provable Inc.
2// This file is part of the Leo library.
3
4// The Leo library is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// The Leo library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
16
17use crate::CompilerState;
18
19use leo_ast::{Expression, Node, NodeID, interpreter_value::Value};
20use leo_errors::StaticAnalyzerError;
21use leo_span::{Span, Symbol};
22
23pub struct ConstPropagationVisitor<'a> {
24    pub state: &'a mut CompilerState,
25    /// The program name.
26    pub program: Symbol,
27    /// The module name.
28    pub module: Vec<Symbol>,
29    /// Have we actually modified the program at all?
30    pub changed: bool,
31    /// The RHS of a const declaration we were not able to evaluate.
32    pub const_not_evaluated: Option<Span>,
33    /// An array index which was not able to be evaluated.
34    pub array_index_not_evaluated: Option<Span>,
35    /// An array length which was not able to be evaluated.
36    pub array_length_not_evaluated: Option<Span>,
37    /// A repeat expression count which was not able to be evaluated.
38    pub repeat_count_not_evaluated: Option<Span>,
39}
40
41impl ConstPropagationVisitor<'_> {
42    /// Enter the symbol table's scope `id`, execute `func`, and then return to the parent scope.
43    pub fn in_scope<T>(&mut self, id: NodeID, func: impl FnOnce(&mut Self) -> T) -> T {
44        self.state.symbol_table.enter_scope(Some(id));
45        let result = func(self);
46        self.state.symbol_table.enter_parent();
47        result
48    }
49
50    /// Enter module scope with path `module`, execute `func`, and then return to the parent module.
51    pub fn in_module_scope<T>(&mut self, module: &[Symbol], func: impl FnOnce(&mut Self) -> T) -> T {
52        let parent_module = self.module.clone();
53        self.module = module.to_vec();
54        let result = func(self);
55        self.module = parent_module;
56        result
57    }
58
59    /// Emit a `StaticAnalyzerError`.
60    pub fn emit_err(&self, err: StaticAnalyzerError) {
61        self.state.handler.emit_err(err);
62    }
63
64    pub fn value_to_expression(&self, value: &Value, span: Span, id: NodeID) -> Option<Expression> {
65        let ty = self.state.type_table.get(&id)?;
66        let symbol_table = &self.state.symbol_table;
67        let struct_lookup = |sym: &[Symbol]| {
68            symbol_table
69                .lookup_struct(sym)
70                .unwrap()
71                .members
72                .iter()
73                .map(|mem| (mem.identifier.name, mem.type_.clone()))
74                .collect()
75        };
76        value.to_expression(span, &self.state.node_builder, &ty, &struct_lookup)
77    }
78
79    pub fn value_to_expression_node(&self, value: &Value, previous: &impl Node) -> Option<Expression> {
80        self.value_to_expression(value, previous.span(), previous.id())
81    }
82}