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        AssociatedFunctionExpression {
66            variant: Identifier::new(sym::Mapping, self.state.node_builder.next_id()),
67            name: Identifier::new(Symbol::intern("get_or_use"), self.state.node_builder.next_id()),
68            type_parameters: vec![],
69            arguments: vec![len_path_expr, self.literal_false(), self.literal_zero_u32()],
70            span,
71            id: self.state.node_builder.next_id(),
72        }
73        .into()
74    }
75
76    /// Generates `Mapping::set(path_expr, key_expr, value_expr)`
77    pub fn set_mapping_expr(
78        &mut self,
79        path_expr: Expression,
80        key_expr: Expression,
81        value_expr: Expression,
82        span: Span,
83    ) -> Expression {
84        AssociatedFunctionExpression {
85            variant: Identifier::new(sym::Mapping, self.state.node_builder.next_id()),
86            name: Identifier::new(Symbol::intern("set"), self.state.node_builder.next_id()),
87            type_parameters: vec![],
88            arguments: vec![path_expr, key_expr, value_expr],
89            span,
90            id: self.state.node_builder.next_id(),
91        }
92        .into()
93    }
94
95    /// Generates `Mapping::get(path_expr, key_expr)`
96    pub fn get_mapping_expr(&mut self, path_expr: Expression, key_expr: Expression, span: Span) -> Expression {
97        AssociatedFunctionExpression {
98            variant: Identifier::new(sym::Mapping, self.state.node_builder.next_id()),
99            name: Identifier::new(Symbol::intern("get"), self.state.node_builder.next_id()),
100            type_parameters: vec![],
101            arguments: vec![path_expr, key_expr],
102            span,
103            id: self.state.node_builder.next_id(),
104        }
105        .into()
106    }
107
108    /// Generates `Mapping::get_or_use(path_expr, key_expr, default_expr)`
109    pub fn get_or_use_mapping_expr(
110        &mut self,
111        path_expr: Expression,
112        key_expr: Expression,
113        default_expr: Expression,
114        span: Span,
115    ) -> Expression {
116        AssociatedFunctionExpression {
117            variant: Identifier::new(sym::Mapping, self.state.node_builder.next_id()),
118            name: Identifier::new(Symbol::intern("get_or_use"), self.state.node_builder.next_id()),
119            type_parameters: vec![],
120            arguments: vec![path_expr, key_expr, default_expr],
121            span,
122            id: self.state.node_builder.next_id(),
123        }
124        .into()
125    }
126
127    /// Generates a ternary expression
128    pub fn ternary_expr(
129        &mut self,
130        condition: Expression,
131        if_true: Expression,
132        if_false: Expression,
133        span: Span,
134    ) -> Expression {
135        TernaryExpression { condition, if_true, if_false, span, id: self.state.node_builder.next_id() }.into()
136    }
137
138    /// Generates a binary expression
139    pub fn binary_expr(&mut self, left: Expression, op: BinaryOperation, right: Expression) -> Expression {
140        BinaryExpression { op, left, right, span: Span::default(), id: self.state.node_builder.next_id() }.into()
141    }
142
143    /// Produces a zero expression for `Type` `ty`.
144    pub fn zero(&self, ty: &Type) -> Expression {
145        // zero value for element type (used as default in get_or_use)
146        let symbol_table = &self.state.symbol_table;
147        let struct_lookup = |sym: &[Symbol]| {
148            symbol_table
149                .lookup_struct(sym)
150                .unwrap()
151                .members
152                .iter()
153                .map(|mem| (mem.identifier.name, mem.type_.clone()))
154                .collect()
155        };
156        Expression::zero(ty, Span::default(), &self.state.node_builder, &struct_lookup)
157            .expect("zero value generation failed")
158    }
159}