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::{
20    ArrayExpression,
21    Expression,
22    Identifier,
23    IntegerType,
24    Literal,
25    NodeBuilder,
26    NodeID,
27    RepeatExpression,
28    StructExpression,
29    StructVariableInitializer,
30    TupleExpression,
31    interpreter_value::Value,
32};
33use leo_errors::StaticAnalyzerError;
34use leo_span::{Span, Symbol};
35
36pub struct ConstPropagationVisitor<'a> {
37    pub state: &'a mut CompilerState,
38    /// The program name.
39    pub program: Symbol,
40    /// Have we actually modified the program at all?
41    pub changed: bool,
42    /// The RHS of a const declaration we were not able to evaluate.
43    pub const_not_evaluated: Option<Span>,
44    /// An array index which was not able to be evaluated.
45    pub array_index_not_evaluated: Option<Span>,
46    /// An array length which was not able to be evaluated.
47    pub array_length_not_evaluated: Option<Span>,
48    /// A repeat expression count which was not able to be evaluated.
49    pub repeat_count_not_evaluated: Option<Span>,
50}
51
52impl ConstPropagationVisitor<'_> {
53    /// Enter the symbol table's scope `id`, execute `func`, and then return to the parent scope.
54    pub fn in_scope<T>(&mut self, id: NodeID, func: impl FnOnce(&mut Self) -> T) -> T {
55        self.state.symbol_table.enter_scope(Some(id));
56        let result = func(self);
57        self.state.symbol_table.enter_parent();
58        result
59    }
60
61    /// Emit a `StaticAnalyzerError`.
62    pub fn emit_err(&self, err: StaticAnalyzerError) {
63        self.state.handler.emit_err(err);
64    }
65}
66
67pub fn value_to_expression(value: &Value, span: Span, node_builder: &NodeBuilder) -> Option<Expression> {
68    use Value::*;
69    let id = node_builder.next_id();
70
71    let result = match value {
72        Unit => leo_ast::UnitExpression { span, id }.into(),
73        Bool(x) => Literal::boolean(*x, span, id).into(),
74        U8(x) => Literal::integer(IntegerType::U8, format!("{x}"), span, id).into(),
75        U16(x) => Literal::integer(IntegerType::U16, format!("{x}"), span, id).into(),
76        U32(x) => Literal::integer(IntegerType::U32, format!("{x}"), span, id).into(),
77        U64(x) => Literal::integer(IntegerType::U64, format!("{x}"), span, id).into(),
78        U128(x) => Literal::integer(IntegerType::U128, format!("{x}"), span, id).into(),
79        I8(x) => Literal::integer(IntegerType::I8, format!("{x}"), span, id).into(),
80        I16(x) => Literal::integer(IntegerType::I16, format!("{x}"), span, id).into(),
81        I32(x) => Literal::integer(IntegerType::I32, format!("{x}"), span, id).into(),
82        I64(x) => Literal::integer(IntegerType::I64, format!("{x}"), span, id).into(),
83        I128(x) => Literal::integer(IntegerType::I128, format!("{x}"), span, id).into(),
84        Address(x) => Literal::address(format!("{x}"), span, id).into(),
85        Group(x) => {
86            let mut s = format!("{x}");
87            // Strip off the `group` suffix.
88            s.truncate(s.len() - 5);
89            Literal::group(s, span, id).into()
90        }
91        Field(x) => {
92            let mut s = format!("{x}");
93            // Strip off the `field` suffix.
94            s.truncate(s.len() - 5);
95            Literal::field(s, span, id).into()
96        }
97        Scalar(x) => {
98            let mut s = format!("{x}");
99            // Strip off the `scalar` suffix.
100            s.truncate(s.len() - 6);
101            Literal::scalar(s, span, id).into()
102        }
103        Tuple(x) => {
104            let mut elements = Vec::with_capacity(x.len());
105            for value in x.iter() {
106                elements.push(value_to_expression(value, span, node_builder)?);
107            }
108            TupleExpression { elements, span, id }.into()
109        }
110        Array(x) => {
111            let mut elements = Vec::with_capacity(x.len());
112            for value in x.iter() {
113                elements.push(value_to_expression(value, span, node_builder)?);
114            }
115            ArrayExpression { elements, span, id }.into()
116        }
117        Repeat(expr, count) => RepeatExpression {
118            expr: value_to_expression(expr, span, node_builder)?,
119            count: value_to_expression(count, span, node_builder)?,
120            span,
121            id,
122        }
123        .into(),
124        Struct(x) => StructExpression {
125            name: Identifier { name: x.name, id: node_builder.next_id(), span },
126            members: {
127                let mut members = Vec::with_capacity(x.contents.len());
128                for (name, val) in x.contents.iter() {
129                    let initializer = StructVariableInitializer {
130                        identifier: Identifier { name: *name, id: node_builder.next_id(), span },
131                        expression: Some(value_to_expression(val, span, node_builder)?),
132                        span,
133                        id: node_builder.next_id(),
134                    };
135                    members.push(initializer)
136                }
137                members
138            },
139            span,
140            id,
141        }
142        .into(),
143        Future(..) => return None,
144    };
145
146    Some(result)
147}