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