leo_passes/storage_lowering/
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::*;
20use leo_span::{Span, Symbol, sym};
21
22use indexmap::IndexMap;
23
24pub struct StorageLoweringVisitor<'a> {
25    pub state: &'a mut CompilerState,
26    // The name of the current program scope
27    pub program: Symbol,
28    pub new_mappings: IndexMap<Symbol, Mapping>,
29}
30
31impl StorageLoweringVisitor<'_> {
32    /// Generate mapping names for a vector expression. Each vector is represented using two
33    /// mappings: a mapping for values and a mapping for the length.
34    pub fn generate_mapping_names_for_vector(&self, expr: &Expression) -> (Symbol, Symbol) {
35        let path = match expr {
36            Expression::Path(path) => path,
37            _ => panic!("Expected path expression for vector"),
38        };
39        let base_sym = path.identifier().name;
40        let vec_values_mapping_name = Symbol::intern(&format!("{base_sym}__"));
41        let vec_length_mapping_name = Symbol::intern(&format!("{base_sym}__len__"));
42        (vec_values_mapping_name, vec_length_mapping_name)
43    }
44
45    /// Creates a path expression from a symbol
46    pub fn symbol_to_path_expr(&mut self, sym: Symbol) -> Expression {
47        Expression::Path(Path::from(Identifier::new(sym, self.state.node_builder.next_id())).into_absolute())
48    }
49
50    /// Standard literal expressions used frequently
51    pub fn literal_false(&mut self) -> Expression {
52        Literal::boolean(false, Span::default(), self.state.node_builder.next_id()).into()
53    }
54
55    pub fn literal_zero_u32(&mut self) -> Expression {
56        Literal::integer(IntegerType::U32, "0".to_string(), Span::default(), self.state.node_builder.next_id()).into()
57    }
58
59    pub fn literal_one_u32(&mut self) -> Expression {
60        Literal::integer(IntegerType::U32, "1".to_string(), Span::default(), self.state.node_builder.next_id()).into()
61    }
62
63    /// Generates `_mapping_get_or_use(len_path_expr, false, 0u32)`
64    pub fn get_vector_len_expr(&mut self, len_path_expr: Expression, span: Span) -> Expression {
65        IntrinsicExpression {
66            name: sym::_mapping_get_or_use,
67            type_parameters: vec![],
68            arguments: vec![len_path_expr, self.literal_false(), self.literal_zero_u32()],
69            span,
70            id: self.state.node_builder.next_id(),
71        }
72        .into()
73    }
74
75    /// Generates `_mapping_set(path_expr, key_expr, value_expr)`
76    pub fn set_mapping_expr(
77        &mut self,
78        path_expr: Expression,
79        key_expr: Expression,
80        value_expr: Expression,
81        span: Span,
82    ) -> Expression {
83        IntrinsicExpression {
84            name: sym::_mapping_set,
85            type_parameters: vec![],
86            arguments: vec![path_expr, key_expr, value_expr],
87            span,
88            id: self.state.node_builder.next_id(),
89        }
90        .into()
91    }
92
93    /// Generates `_mapping_get(path_expr, key_expr)`
94    pub fn get_mapping_expr(&mut self, path_expr: Expression, key_expr: Expression, span: Span) -> Expression {
95        IntrinsicExpression {
96            name: sym::_mapping_get,
97            type_parameters: vec![],
98            arguments: vec![path_expr, key_expr],
99            span,
100            id: self.state.node_builder.next_id(),
101        }
102        .into()
103    }
104
105    /// Generates `_mapping_get_or_use(path_expr, key_expr, default_expr)`
106    pub fn get_or_use_mapping_expr(
107        &mut self,
108        path_expr: Expression,
109        key_expr: Expression,
110        default_expr: Expression,
111        span: Span,
112    ) -> Expression {
113        IntrinsicExpression {
114            name: sym::_mapping_get_or_use,
115            type_parameters: vec![],
116            arguments: vec![path_expr, key_expr, default_expr],
117            span,
118            id: self.state.node_builder.next_id(),
119        }
120        .into()
121    }
122
123    /// Generates a ternary expression
124    pub fn ternary_expr(
125        &mut self,
126        condition: Expression,
127        if_true: Expression,
128        if_false: Expression,
129        span: Span,
130    ) -> Expression {
131        TernaryExpression { condition, if_true, if_false, span, id: self.state.node_builder.next_id() }.into()
132    }
133
134    /// Generates a binary expression
135    pub fn binary_expr(&mut self, left: Expression, op: BinaryOperation, right: Expression) -> Expression {
136        BinaryExpression { op, left, right, span: Span::default(), id: self.state.node_builder.next_id() }.into()
137    }
138
139    /// Produces a zero expression for `Type` `ty`.
140    pub fn zero(&self, ty: &Type) -> Expression {
141        // zero value for element type (used as default in get_or_use)
142        let symbol_table = &self.state.symbol_table;
143        let struct_lookup = |sym: &[Symbol]| {
144            symbol_table
145                .lookup_struct(sym)
146                .unwrap()
147                .members
148                .iter()
149                .map(|mem| (mem.identifier.name, mem.type_.clone()))
150                .collect()
151        };
152        Expression::zero(ty, Span::default(), &self.state.node_builder, &struct_lookup)
153            .expect("zero value generation failed")
154    }
155}