Skip to main content

leo_ast/functions/
mod.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
17mod annotation;
18pub use annotation::*;
19
20mod intrinsic;
21pub use intrinsic::*;
22
23mod variant;
24pub use variant::*;
25
26mod input;
27pub use input::*;
28
29mod output;
30pub use output::*;
31
32mod mode;
33pub use mode::*;
34
35use crate::{Block, ConstParameter, FunctionStub, Identifier, Indent, Node, NodeID, TupleType, TypeKind};
36use leo_span::{Span, Symbol};
37
38use itertools::Itertools as _;
39use serde::Serialize;
40use std::fmt;
41
42/// A function definition.
43#[derive(Clone, Default, Serialize)]
44pub struct Function {
45    /// Whether the `export` keyword was written on this function. `None` means the
46    /// visibility concept does not apply (e.g., program-block functions and
47    /// stubs, which are always reachable as part of the program's public
48    /// interface, and compiler-synthesized helpers).
49    pub is_exported: Option<bool>,
50    /// Annotations on the function.
51    pub annotations: Vec<Annotation>,
52    /// Is this function a transition, inlined, or a regular function?.
53    pub variant: Variant,
54    /// The function identifier, e.g., `foo` in `function foo(...) { ... }`.
55    pub identifier: Identifier,
56    /// The function's const parameters.
57    pub const_parameters: Vec<ConstParameter>,
58    /// The function's input parameters.
59    pub input: Vec<Input>,
60    /// The function's output declarations.
61    pub output: Vec<Output>,
62    /// The function's output type.
63    pub output_type: TypeKind,
64    /// The body of the function.
65    pub block: Block,
66    /// The entire span of the function definition.
67    pub span: Span,
68    /// The ID of the node.
69    pub id: NodeID,
70}
71
72impl PartialEq for Function {
73    fn eq(&self, other: &Self) -> bool {
74        self.identifier == other.identifier
75    }
76}
77
78impl Eq for Function {}
79
80impl Function {
81    /// Initialize a new function.
82    #[allow(clippy::too_many_arguments)]
83    pub fn new(
84        is_exported: Option<bool>,
85        annotations: Vec<Annotation>,
86        variant: Variant,
87        identifier: Identifier,
88        const_parameters: Vec<ConstParameter>,
89        input: Vec<Input>,
90        output: Vec<Output>,
91        block: Block,
92        span: Span,
93        id: NodeID,
94    ) -> Self {
95        let output_type = match output.len() {
96            0 => TypeKind::Unit,
97            1 => output[0].type_.kind().clone(),
98            _ => TypeKind::Tuple(TupleType::new(output.iter().map(|o| o.type_.kind().clone()).collect())),
99        };
100
101        Function {
102            is_exported,
103            annotations,
104            variant,
105            identifier,
106            const_parameters,
107            input,
108            output,
109            output_type,
110            block,
111            span,
112            id,
113        }
114    }
115
116    /// Returns function name.
117    pub fn name(&self) -> Symbol {
118        self.identifier.name
119    }
120
121    /// Returns `true` if any output of the function is a `Final`
122    pub fn has_final_output(&self) -> bool {
123        self.output.iter().any(|o| matches!(o.type_.kind(), TypeKind::Future(_)))
124    }
125
126    /// Returns `true` if the function carries an `@test` annotation.
127    pub fn is_test(&self) -> bool {
128        self.annotations.iter().any(|a| a.identifier.name == leo_span::sym::test)
129    }
130}
131
132impl From<FunctionStub> for Function {
133    fn from(function: FunctionStub) -> Self {
134        Self {
135            is_exported: None,
136            annotations: function.annotations,
137            variant: function.variant,
138            identifier: function.identifier,
139            const_parameters: vec![],
140            input: function.input,
141            output: function.output,
142            output_type: function.output_type,
143            block: Block::default(),
144            span: function.span,
145            id: function.id,
146        }
147    }
148}
149
150impl fmt::Debug for Function {
151    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
152        write!(f, "{self}")
153    }
154}
155
156impl fmt::Display for Function {
157    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
158        for annotation in &self.annotations {
159            writeln!(f, "{annotation}")?;
160        }
161
162        if self.is_exported == Some(true) {
163            write!(f, "export ")?;
164        }
165
166        match self.variant {
167            Variant::FinalFn => write!(f, "final fn ")?,
168            Variant::Fn => write!(f, "fn ")?,
169            Variant::Finalize => write!(f, "finalize ")?,
170            Variant::EntryPoint => write!(f, "fn ")?,
171            Variant::View => write!(f, "view fn ")?,
172        }
173
174        write!(f, "{}", self.identifier)?;
175        if !self.const_parameters.is_empty() {
176            write!(f, "::[{}]", self.const_parameters.iter().format(", "))?;
177        }
178        write!(f, "({})", self.input.iter().format(", "))?;
179
180        match self.output.len() {
181            0 => {}
182            1 => {
183                if !matches!(self.output[0].type_.kind(), TypeKind::Unit) {
184                    write!(f, " -> {}", self.output[0])?;
185                }
186            }
187            _ => {
188                write!(f, " -> ({})", self.output.iter().format(", "))?;
189            }
190        }
191
192        writeln!(f, " {{")?;
193        for stmt in self.block.statements.iter() {
194            writeln!(f, "{}{}", Indent(stmt), stmt.semicolon())?;
195        }
196        write!(f, "}}")
197    }
198}
199
200crate::simple_node_impl!(Function);