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, Type};
36use leo_span::{Span, Symbol};
37
38use itertools::Itertools as _;
39use serde::{Deserialize, Serialize};
40use std::fmt;
41
42/// A function definition.
43#[derive(Clone, Default, Serialize, Deserialize)]
44pub struct Function {
45    /// Annotations on the function.
46    pub annotations: Vec<Annotation>,
47    /// Is this function a transition, inlined, or a regular function?.
48    pub variant: Variant,
49    /// The function identifier, e.g., `foo` in `function foo(...) { ... }`.
50    pub identifier: Identifier,
51    /// The function's const parameters.
52    pub const_parameters: Vec<ConstParameter>,
53    /// The function's input parameters.
54    pub input: Vec<Input>,
55    /// The function's output declarations.
56    pub output: Vec<Output>,
57    /// The function's output type.
58    pub output_type: Type,
59    /// The body of the function.
60    pub block: Block,
61    /// The entire span of the function definition.
62    pub span: Span,
63    /// The ID of the node.
64    pub id: NodeID,
65}
66
67impl PartialEq for Function {
68    fn eq(&self, other: &Self) -> bool {
69        self.identifier == other.identifier
70    }
71}
72
73impl Eq for Function {}
74
75impl Function {
76    /// Initialize a new function.
77    #[allow(clippy::too_many_arguments)]
78    pub fn new(
79        annotations: Vec<Annotation>,
80        variant: Variant,
81        identifier: Identifier,
82        const_parameters: Vec<ConstParameter>,
83        input: Vec<Input>,
84        output: Vec<Output>,
85        block: Block,
86        span: Span,
87        id: NodeID,
88    ) -> Self {
89        let output_type = match output.len() {
90            0 => Type::Unit,
91            1 => output[0].type_.clone(),
92            _ => Type::Tuple(TupleType::new(output.iter().map(|o| o.type_.clone()).collect())),
93        };
94
95        Function { annotations, variant, identifier, const_parameters, input, output, output_type, block, span, id }
96    }
97
98    /// Returns function name.
99    pub fn name(&self) -> Symbol {
100        self.identifier.name
101    }
102
103    /// Returns `true` if any output of the function is a `Final`
104    pub fn has_final_output(&self) -> bool {
105        self.output.iter().any(|o| matches!(o.type_, Type::Future(_)))
106    }
107}
108
109impl From<FunctionStub> for Function {
110    fn from(function: FunctionStub) -> Self {
111        Self {
112            annotations: function.annotations,
113            variant: function.variant,
114            identifier: function.identifier,
115            const_parameters: vec![],
116            input: function.input,
117            output: function.output,
118            output_type: function.output_type,
119            block: Block::default(),
120            span: function.span,
121            id: function.id,
122        }
123    }
124}
125
126impl fmt::Debug for Function {
127    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
128        write!(f, "{self}")
129    }
130}
131
132impl fmt::Display for Function {
133    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
134        for annotation in &self.annotations {
135            writeln!(f, "{annotation}")?;
136        }
137
138        match self.variant {
139            Variant::FinalFn => write!(f, "final fn ")?,
140            Variant::Fn => write!(f, "fn ")?,
141            Variant::Finalize => write!(f, "finalize ")?,
142            Variant::EntryPoint => write!(f, "fn ")?,
143        }
144
145        write!(f, "{}", self.identifier)?;
146        if !self.const_parameters.is_empty() {
147            write!(f, "::[{}]", self.const_parameters.iter().format(", "))?;
148        }
149        write!(f, "({})", self.input.iter().format(", "))?;
150
151        match self.output.len() {
152            0 => {}
153            1 => {
154                if !matches!(self.output[0].type_, Type::Unit) {
155                    write!(f, " -> {}", self.output[0])?;
156                }
157            }
158            _ => {
159                write!(f, " -> ({})", self.output.iter().format(", "))?;
160            }
161        }
162
163        writeln!(f, " {{")?;
164        for stmt in self.block.statements.iter() {
165            writeln!(f, "{}{}", Indent(stmt), stmt.semicolon())?;
166        }
167        write!(f, "}}")
168    }
169}
170
171crate::simple_node_impl!(Function);