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