Skip to main content

leo_ast/interface/
prototypes.rs

1// Copyright (C) 2019-2026 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 std::fmt;
18
19use crate::{
20    Annotation,
21    ConstParameter,
22    Identifier,
23    Input,
24    Member,
25    Node,
26    NodeID,
27    Output,
28    TupleType,
29    Type,
30    Variant,
31    indent_display::Indent,
32};
33use itertools::Itertools;
34use leo_span::Span;
35use serde::{Deserialize, Serialize};
36
37/// A mapping prototype in an interface, e.g. `mapping balances: address => u128;`.
38#[derive(Clone, Default, Debug, Serialize, Deserialize)]
39pub struct MappingPrototype {
40    /// The name of the mapping.
41    pub identifier: Identifier,
42    /// The type of the key.
43    pub key_type: Type,
44    /// The type of the value.
45    pub value_type: Type,
46    /// The entire span of the mapping prototype.
47    pub span: Span,
48    /// The ID of the node.
49    pub id: NodeID,
50}
51
52impl PartialEq for MappingPrototype {
53    fn eq(&self, other: &Self) -> bool {
54        self.identifier == other.identifier
55    }
56}
57
58impl Eq for MappingPrototype {}
59
60impl fmt::Display for MappingPrototype {
61    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
62        write!(f, "mapping {}: {} => {};", self.identifier, self.key_type, self.value_type)
63    }
64}
65
66crate::simple_node_impl!(MappingPrototype);
67
68/// A storage variable prototype in an interface, e.g. `storage counter: u32;`.
69#[derive(Clone, Default, Debug, Serialize, Deserialize)]
70pub struct StorageVariablePrototype {
71    /// The name of the storage variable.
72    pub identifier: Identifier,
73    /// The type of the variable.
74    pub type_: Type,
75    /// The entire span of the storage variable prototype.
76    pub span: Span,
77    /// The ID of the node.
78    pub id: NodeID,
79}
80
81impl PartialEq for StorageVariablePrototype {
82    fn eq(&self, other: &Self) -> bool {
83        self.identifier == other.identifier
84    }
85}
86
87impl Eq for StorageVariablePrototype {}
88
89impl fmt::Display for StorageVariablePrototype {
90    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
91        write!(f, "storage {}: {};", self.identifier, self.type_)
92    }
93}
94
95crate::simple_node_impl!(StorageVariablePrototype);
96
97#[derive(Clone, Default, Serialize, Deserialize)]
98pub struct FunctionPrototype {
99    /// Annotations on the function.
100    pub annotations: Vec<Annotation>,
101    /// `Variant::EntryPoint` for a plain `fn name(...)` prototype, `Variant::View` for
102    /// `view fn name(...)`. These are the only externally-callable variants and the only
103    /// variants permitted in interface position.
104    pub variant: Variant,
105    /// The function identifier, e.g., `foo` in `function foo(...) { ... }`.
106    pub identifier: Identifier,
107    /// The function's const parameters.
108    pub const_parameters: Vec<ConstParameter>,
109    /// The function's input parameters.
110    pub input: Vec<Input>,
111    /// The function's output declarations.
112    pub output: Vec<Output>,
113    /// The function's output type.
114    pub output_type: Type,
115    /// The entire span of the function definition.
116    pub span: Span,
117    /// The ID of the node.
118    pub id: NodeID,
119}
120
121impl FunctionPrototype {
122    #[allow(clippy::too_many_arguments)]
123    pub fn new(
124        annotations: Vec<Annotation>,
125        variant: Variant,
126        identifier: Identifier,
127        const_parameters: Vec<ConstParameter>,
128        input: Vec<Input>,
129        output: Vec<Output>,
130        span: Span,
131        id: NodeID,
132    ) -> Self {
133        let output_type = match output.len() {
134            0 => Type::Unit,
135            1 => output[0].type_.clone(),
136            _ => Type::Tuple(TupleType::new(output.iter().map(|o| o.type_.clone()).collect())),
137        };
138
139        Self { annotations, variant, identifier, const_parameters, input, output, output_type, span, id }
140    }
141}
142
143impl PartialEq for FunctionPrototype {
144    fn eq(&self, other: &Self) -> bool {
145        self.identifier == other.identifier
146    }
147}
148
149impl Eq for FunctionPrototype {}
150
151impl fmt::Debug for FunctionPrototype {
152    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
153        write!(f, "{self}")
154    }
155}
156
157impl fmt::Display for FunctionPrototype {
158    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
159        for annotation in &self.annotations {
160            writeln!(f, "{annotation}")?;
161        }
162        match self.variant {
163            Variant::View => write!(f, "view fn {}", self.identifier)?,
164            Variant::EntryPoint => write!(f, "fn {}", self.identifier)?,
165            v => panic!(
166                "FunctionPrototype constructed with invalid variant `{v:?}`; only `EntryPoint` or `View` are allowed"
167            ),
168        }
169        if !self.const_parameters.is_empty() {
170            write!(f, "::[{}]", self.const_parameters.iter().format(", "))?;
171        }
172        write!(f, "({})", self.input.iter().format(", "))?;
173        match self.output.len() {
174            0 => {}
175            1 => {
176                if !matches!(self.output[0].type_, Type::Unit) {
177                    write!(f, " -> {}", self.output[0])?;
178                }
179            }
180            _ => {
181                write!(f, " -> ({})", self.output.iter().format(", "))?;
182            }
183        }
184        write!(f, ";")
185    }
186}
187
188crate::simple_node_impl!(FunctionPrototype);
189
190#[derive(Clone, Default, Serialize, Deserialize)]
191pub struct RecordPrototype {
192    /// The record identifier
193    pub identifier: Identifier,
194    /// The fields of this record prototype, if any.
195    pub members: Vec<Member>,
196    /// The entire span of the composite definition.
197    pub span: Span,
198    /// The ID of the node.
199    pub id: NodeID,
200}
201
202impl PartialEq for RecordPrototype {
203    fn eq(&self, other: &Self) -> bool {
204        self.identifier == other.identifier
205    }
206}
207
208impl Eq for RecordPrototype {}
209
210impl fmt::Debug for RecordPrototype {
211    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
212        write!(f, "{self}")
213    }
214}
215
216impl fmt::Display for RecordPrototype {
217    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
218        writeln!(f, " record {} {{", self.identifier)?;
219
220        for field in self.members.iter() {
221            writeln!(f, "{},", Indent(field))?;
222        }
223        write!(f, "}}")
224    }
225}
226
227crate::simple_node_impl!(RecordPrototype);